llvm_support/
align.rs

1//! A typesafe representation of alignment states and operations that
2//! preserves LLVM's alignment invariants.
3
4use std::cmp::Ordering;
5use std::convert::{TryFrom, TryInto};
6use std::fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult};
7use std::num::ParseIntError;
8use std::str::FromStr;
9
10use paste::paste;
11use thiserror::Error;
12
13/// Errors that can occur when constructing an [`Align`](Align)
14#[derive(Debug, Error)]
15pub enum AlignError {
16    /// The shift would exceed our maximum shift value.
17    #[error("supplied shift is too large ({0} > {})", Align::MAX_SHIFT)]
18    ShiftTooBig(u8),
19    /// The input used to compute the shift is not a power of two.
20    #[error("supplied value is not a power of two: {0}")]
21    NotPowerOfTwo(u64),
22    /// The input used to compute the shift is not a byte multiple.
23    #[error("supplied value is not a multiple of 8: {0}")]
24    NotByteMultiple(u64),
25}
26
27/// A size efficient, opaque representation of bytewise alignment.
28///
29/// See `Alignment.h` for LLVM's corresponding structures.
30#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
31pub struct Align(u8);
32
33impl Debug for Align {
34    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
35        f.debug_struct("Align")
36            .field("byte_align", &self.byte_align())
37            .finish()
38    }
39}
40
41impl Display for Align {
42    fn fmt(&self, f: &mut Formatter) -> FmtResult {
43        write!(f, "{}", self.byte_align())
44    }
45}
46
47macro_rules! make_const_align {
48    ($align:literal, $shift:literal) => {
49        paste! {
50            /// A convenience handle for types of exactly $width bits.
51            pub const [< ALIGN $align >]: Align = Align($shift);
52        }
53    };
54}
55
56impl Align {
57    /// The maximum alignment shift representable with this type.
58    pub const MAX_SHIFT: u8 = 63;
59
60    make_const_align!(8, 0);
61    make_const_align!(16, 1);
62    make_const_align!(32, 2);
63    make_const_align!(64, 3);
64    make_const_align!(128, 4);
65
66    /// Returns whether `value` is a power of two, for `value > 0`.
67    #[inline(always)]
68    fn is_pow2(value: u64) -> bool {
69        (value > 0) && ((value & (value - 1)) == 0)
70    }
71
72    /// Returns the log2 of `value`, for `value > 0`. The result is floored.
73    #[inline(always)]
74    fn log2(value: u64) -> u8 {
75        // NOTE(ww): u8 truncation is sound here, since log2(u64::MAX) == 64.
76        ((u64::from(u64::BITS) - 1) - u64::from(value.leading_zeros())) as u8
77    }
78
79    /// Create an `Align` from the given shift value, returning an error if the requested
80    /// shift is invalid.
81    pub fn from_shift(shift: u8) -> Result<Align, AlignError> {
82        match shift > Align::MAX_SHIFT {
83            false => Ok(Align(shift)),
84            true => Err(AlignError::ShiftTooBig(shift)),
85        }
86    }
87
88    /// Create an `Align` from the given byte alignment value, returning an error if the requested
89    /// shift is invalid.
90    pub fn from_byte_align(byte_align: u64) -> Result<Align, AlignError> {
91        match Align::is_pow2(byte_align) {
92            true => Align::from_shift(Align::log2(byte_align)),
93            false => Err(AlignError::NotPowerOfTwo(byte_align)),
94        }
95    }
96
97    /// Create an `Align` from the given bit alignment value, returning an error if the requested
98    /// shift is invalid.
99    pub fn from_bit_align(bit_align: u64) -> Result<Align, AlignError> {
100        match bit_align % 8 == 0 {
101            true => Align::from_byte_align(bit_align / 8),
102            false => Err(AlignError::NotByteMultiple(bit_align)),
103        }
104    }
105
106    /// Return this alignment's shift value, i.e. the power of two for the alignment.
107    pub fn shift(&self) -> u8 {
108        self.0
109    }
110
111    /// Return this alignment as a byte-granular alignment.
112    pub fn byte_align(&self) -> u64 {
113        1 << self.0
114    }
115
116    /// Return this alignment as a bit-granular alignment.
117    pub fn bit_align(&self) -> u64 {
118        self.byte_align() * 8
119    }
120}
121
122/// Errors that can occur when constructing an [`AlignedTypeWidth`](AlignedTypeWidth)
123#[derive(Debug, Error)]
124pub enum AlignedTypeWidthError {
125    /// The requested bit width is zero, which is nonsense (every non-aggregate type
126    /// carries a nonzero width).
127    #[error("bit width for type cannot be zero")]
128    Zero,
129    /// The requested bit width exceeds our support.
130    #[error(
131        "bit width for type is too large ({0} > {} bits)",
132        AlignedTypeWidth::MAX
133    )]
134    TooBig(u32),
135}
136
137/// Represents a potentially unknown (unspecified) alignment.
138#[derive(Copy, Clone, Debug, PartialEq)]
139pub struct MaybeAlign(Option<Align>);
140
141impl TryFrom<u8> for MaybeAlign {
142    type Error = AlignError;
143
144    fn try_from(value: u8) -> Result<MaybeAlign, AlignError> {
145        match value {
146            0 => Ok(MaybeAlign(None)),
147            _ => Ok(MaybeAlign(Some(Align::from_shift(value - 1)?))),
148        }
149    }
150}
151
152/// An invariant-preserving newtype for representing the bitwidth of an
153/// alignable type.
154#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
155pub struct AlignedTypeWidth(u32);
156
157macro_rules! make_const_width {
158    ($width:literal) => {
159        paste! {
160            /// A convenience handle for types of exactly $width bits.
161            pub const [< WIDTH $width >]: AlignedTypeWidth = AlignedTypeWidth($width);
162        }
163    };
164}
165
166impl AlignedTypeWidth {
167    /// The maximum type width, in bits, representable in this structure.
168    pub const MAX: u32 = (1 << 23) - 1;
169
170    // Common infallible widths, for convenience.
171    make_const_width!(1);
172    make_const_width!(8);
173    make_const_width!(16);
174    make_const_width!(32);
175    make_const_width!(64);
176    make_const_width!(128);
177}
178
179impl TryFrom<u32> for AlignedTypeWidth {
180    type Error = AlignedTypeWidthError;
181    fn try_from(value: u32) -> Result<Self, Self::Error> {
182        match value > 0 && value <= AlignedTypeWidth::MAX {
183            true => Ok(AlignedTypeWidth(value)),
184            false => Err(AlignedTypeWidthError::TooBig(value)),
185        }
186    }
187}
188
189/// An enumeration of alignable non-pointer types.
190#[derive(Copy, Clone, Debug, Eq, PartialEq)]
191pub enum AlignedType {
192    /// Aggregate types.
193    Aggregate,
194    /// Floating point types.
195    Float(AlignedTypeWidth),
196    /// Integer types.
197    Integer(AlignedTypeWidth),
198    /// Vector types.
199    Vector(AlignedTypeWidth),
200}
201
202impl PartialOrd for AlignedType {
203    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
204        Some(self.cmp(other))
205    }
206}
207
208impl Ord for AlignedType {
209    fn cmp(&self, other: &Self) -> Ordering {
210        match (self, other) {
211            // AlignedTypes are ordered first by their type, and then by their bitwidth.
212            // Per LLVM, the type ordering is: aggregate < float < integer < vector.
213
214            // Aggregate types are ordered lowest. They don't have a width, so two
215            // aggregate types are always equal.
216            (AlignedType::Aggregate, AlignedType::Aggregate) => Ordering::Equal,
217            (AlignedType::Aggregate, _) => Ordering::Less,
218
219            // Float types are ordered second lowest.
220            (AlignedType::Float(_), AlignedType::Aggregate) => Ordering::Greater,
221            (AlignedType::Float(lhs), AlignedType::Float(rhs)) => lhs.cmp(rhs),
222            (AlignedType::Float(_), AlignedType::Integer(_) | AlignedType::Vector(_)) => {
223                Ordering::Less
224            }
225
226            // Integer types are ordered third lowest.
227            (AlignedType::Integer(_), AlignedType::Aggregate | AlignedType::Float(_)) => {
228                Ordering::Greater
229            }
230            (AlignedType::Integer(lhs), AlignedType::Integer(rhs)) => lhs.cmp(rhs),
231            (AlignedType::Integer(_), AlignedType::Vector(_)) => Ordering::Less,
232
233            // Vector types are ordered highest.
234            (
235                AlignedType::Vector(_),
236                AlignedType::Aggregate | AlignedType::Float(_) | AlignedType::Integer(_),
237            ) => Ordering::Greater,
238            (AlignedType::Vector(lhs), AlignedType::Vector(rhs)) => lhs.cmp(rhs),
239        }
240    }
241}
242
243macro_rules! make_const_aligned {
244    ($name:ident, $width:literal) => {
245        paste! {
246            /// A $width bit $name:lower, subject to some alignment rules.
247            pub const [< $name:upper $width >]: AlignedType = AlignedType::$name(AlignedTypeWidth::[< WIDTH $width >]);
248        }
249    }
250}
251
252impl AlignedType {
253    // Common infallible aligned types, for convenience.
254    make_const_aligned!(Float, 16);
255    make_const_aligned!(Float, 32);
256    make_const_aligned!(Float, 64);
257    make_const_aligned!(Float, 128);
258    make_const_aligned!(Integer, 1);
259    make_const_aligned!(Integer, 8);
260    make_const_aligned!(Integer, 16);
261    make_const_aligned!(Integer, 32);
262    make_const_aligned!(Integer, 64);
263}
264
265/// Errors that can occur when constructing a [`TypeAlignSpec`](TypeAlignSpec)
266/// or [`PointerAlignSpec`](PointerAlignSpec).
267#[derive(Debug, Error)]
268pub enum AlignSpecError {
269    /// The underlying type being specified has a bad width.
270    #[error("impossible bit width for underlying aligned type")]
271    BadTypeWidth(#[from] AlignedTypeWidthError),
272    /// The supplied preferred alignment isn't greater than or equal to the ABI minimum
273    #[error("impossible preferred alignment: {0} must be >= {1}")]
274    AlignPref(Align, Align),
275    /// The supplied ABI alignment is too large.
276    #[error(
277        "impossible ABI alignment for type: {0} > {}",
278        TypeAlignSpec::MAX_ALIGN
279    )]
280    AbiAlignTooLarge(Align),
281    /// We're parsing this alignment spec from a string, and it's malformed in some way.
282    #[error("error while parsing alignment spec: {0}")]
283    Parse(String),
284    /// We're parsing this alignment spec from a string, and one of its inner alignments
285    /// is malformed in some way.
286    #[error("error while parsing inner alignment in spec")]
287    ParseAlign(#[from] AlignError),
288    /// We're parsing this alignment spec from a string, and one of its fields can't be converted
289    /// into an integer.
290    #[error("error while parsing integer in alignment spec")]
291    BadInt(#[from] ParseIntError),
292    /// The supplied address space is invalid.
293    #[error("invalid address space in spec")]
294    BadAddressSpace(#[from] AddressSpaceError),
295}
296
297/// Represents an alignable type, along with its ABI-mandated and
298/// preferred alignments (which may differ).
299#[non_exhaustive]
300#[derive(Debug, Copy, Clone, Eq)]
301pub struct TypeAlignSpec {
302    /// The type being aligned.
303    pub aligned_type: AlignedType,
304    /// The ABI-enforced alignment for the type.
305    pub abi_alignment: Align,
306    /// The preferred alignment for the type.
307    ///
308    /// NOTE: This **must** be greater than or equal to the ABI alignment.
309    /// This invariant is preserved during construction.
310    pub preferred_alignment: Align,
311}
312
313impl PartialEq for TypeAlignSpec {
314    fn eq(&self, other: &Self) -> bool {
315        self.aligned_type == other.aligned_type
316    }
317}
318
319impl PartialOrd for TypeAlignSpec {
320    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
321        Some(self.aligned_type.cmp(&other.aligned_type))
322    }
323}
324
325impl Ord for TypeAlignSpec {
326    fn cmp(&self, other: &Self) -> Ordering {
327        self.aligned_type.cmp(&other.aligned_type)
328    }
329}
330
331impl FromStr for TypeAlignSpec {
332    type Err = AlignSpecError;
333
334    fn from_str(value: &str) -> Result<Self, Self::Err> {
335        if value.is_empty() {
336            return Err(AlignSpecError::Parse(
337                "cannot parse type alignment from an empty string".into(),
338            ));
339        }
340
341        // Unwrap safety: we check for a nonempty string above.
342        #[allow(clippy::unwrap_used)]
343        let id = value.chars().next().unwrap();
344        let body = &value[1..];
345        let parts: Vec<&str> = body.split(':').collect();
346
347        match id {
348            // `a` marks an aggregate, and is a special parsing case since it
349            // doesn't include a bit size.
350            'a' => {
351                let parts = match body.chars().next() {
352                    Some(':') => body[1..].split(':').collect::<Vec<&str>>(),
353                    Some(o) => {
354                        return Err(AlignSpecError::Parse(format!(
355                            "unexpected character before aggregate spec: {}",
356                            o
357                        )))
358                    }
359                    None => return Err(AlignSpecError::Parse("empty aggregate specifier".into())),
360                };
361
362                if parts.is_empty() {
363                    return Err(AlignSpecError::Parse(format!(
364                        "wrong number of aggregate alignment parameters: expected at least 1, got {}",
365                        parts.len()
366                    )));
367                }
368                let abi = parts[0]
369                    .parse::<u64>()
370                    .map_err(|e| AlignSpecError::Parse(e.to_string()))
371                    .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
372
373                let pref = parts
374                    .get(1)
375                    .map(|p| {
376                        p.parse::<u64>()
377                            .map_err(AlignSpecError::from)
378                            .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
379                    })
380                    .unwrap_or(Ok(abi))?;
381
382                TypeAlignSpec::new(AlignedType::Aggregate, abi, pref)
383            }
384            // All other cases take at least two parameters, and an optional
385            // third for a preferred alignment.
386            id => {
387                if parts.len() < 2 {
388                    return Err(AlignSpecError::Parse(format!(
389                        "wrong number of alignment parameters for spec '{}': expected at least 2, got {}",
390                        id,
391                        parts.len()
392                    )));
393                }
394
395                // TODO(ww): Ugly.
396                let bitsize = parts[0]
397                    .parse::<u32>()
398                    .map_err(|e| AlignSpecError::Parse(e.to_string()))
399                    .and_then(|bs| AlignedTypeWidth::try_from(bs).map_err(Into::into))?;
400                let abi = parts[1]
401                    .parse::<u64>()
402                    .map_err(|e| AlignSpecError::Parse(e.to_string()))
403                    .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
404                let pref = parts
405                    .get(2)
406                    .map(|p| {
407                        p.parse::<u64>()
408                            .map_err(AlignSpecError::from)
409                            .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
410                    })
411                    .unwrap_or(Ok(abi))?;
412
413                match id {
414                    'i' => TypeAlignSpec::new(AlignedType::Integer(bitsize), abi, pref),
415                    'v' => TypeAlignSpec::new(AlignedType::Vector(bitsize), abi, pref),
416                    'f' => TypeAlignSpec::new(AlignedType::Float(bitsize), abi, pref),
417                    o => Err(AlignSpecError::Parse(format!(
418                        "unknown type for align spec: {}",
419                        o
420                    ))),
421                }
422            }
423        }
424    }
425}
426
427impl TypeAlignSpec {
428    /// The maximum type width, in bits, representable in this structure.
429    pub const MAX_TYPE_BIT_WIDTH: u32 = (1 << 23) - 1;
430
431    /// The maximum alignment supported by instances of `TypeAlignSpec`.
432    // NOTE(ww): On top of the normal alignment invariants, `TypeAlignSpec`
433    // requires its alignments to be less than 2^16 bits. This is
434    // to prevent unforeseen compatibility issues.
435    // See: https://reviews.llvm.org/D67400
436    pub const MAX_ALIGN: Align = Align(15);
437
438    /// Create a new `TypeAlignSpec` for the given `AlignedType` and alignment
439    /// constraints.
440    pub fn new(aligned_type: AlignedType, abi: Align, pref: Align) -> Result<Self, AlignSpecError> {
441        if pref < abi {
442            return Err(AlignSpecError::AlignPref(pref, abi));
443        }
444
445        match ((abi <= Self::MAX_ALIGN), (pref <= Self::MAX_ALIGN)) {
446            (true, true) => Ok(Self {
447                aligned_type: aligned_type,
448                abi_alignment: abi,
449                preferred_alignment: pref,
450            }),
451            // NOTE(ww): We don't need a special case for the preferred alignment
452            // being too large here, since it's precluded by our `pref > abi` check
453            // above: `pref > MAX_ALIGN && pref >= abi` implies `abi >= MAX_ALIGN`,
454            // so our ABI value is always erroneous.
455            (_, _) => Err(AlignSpecError::AbiAlignTooLarge(abi)),
456        }
457    }
458}
459
460/// Represents a sorted collection of [`TypeAlignSpec`](TypeAlignSpec)s.
461#[derive(Debug, PartialEq)]
462pub struct TypeAlignSpecs(Vec<TypeAlignSpec>);
463
464impl Default for TypeAlignSpecs {
465    fn default() -> Self {
466        // NOTE: The default sequence here is sorted.
467        // Unwrap safety: each of these constructions is infallible.
468        // TODO(ww): Use macro_rules! here to make each of these `TypeAlignSpec`s
469        // into an infallible constant.
470        #[allow(clippy::unwrap_used)]
471        Self(vec![
472            TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
473            TypeAlignSpec::new(AlignedType::FLOAT16, Align::ALIGN16, Align::ALIGN16).unwrap(),
474            TypeAlignSpec::new(AlignedType::FLOAT32, Align::ALIGN32, Align::ALIGN32).unwrap(),
475            TypeAlignSpec::new(AlignedType::FLOAT64, Align::ALIGN64, Align::ALIGN64).unwrap(),
476            TypeAlignSpec::new(AlignedType::FLOAT128, Align::ALIGN128, Align::ALIGN128).unwrap(),
477            TypeAlignSpec::new(AlignedType::INTEGER1, Align::ALIGN8, Align::ALIGN8).unwrap(),
478            TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN8, Align::ALIGN8).unwrap(),
479            TypeAlignSpec::new(AlignedType::INTEGER16, Align::ALIGN16, Align::ALIGN16).unwrap(),
480            TypeAlignSpec::new(AlignedType::INTEGER32, Align::ALIGN32, Align::ALIGN32).unwrap(),
481            TypeAlignSpec::new(AlignedType::INTEGER64, Align::ALIGN64, Align::ALIGN64).unwrap(),
482        ])
483    }
484}
485
486impl TypeAlignSpecs {
487    /// Update this list of type alignment specifications by inserting the given specification
488    /// at the correct location, **or** rewriting an already present specification.
489    pub fn update(&mut self, spec: TypeAlignSpec) {
490        // Find the position of the rightmost spec that's less than or equal to
491        // the spec that we're inserting.
492        let pos = self.0.iter().rposition(|&other| other <= spec);
493        match pos {
494            // If we have a match, then we need to either insert or update
495            // depending on whether our match is the same spec as us.
496            // Panic safety: `pos` is a valid index returned above.
497            Some(pos) => match self.0[pos] == spec {
498                true => {
499                    // Unwrap safety: `pos` is a valid index returned above.
500                    #[allow(clippy::unwrap_used)]
501                    let mut other = self.0.get_mut(pos).unwrap();
502
503                    other.abi_alignment = spec.abi_alignment;
504                    other.preferred_alignment = spec.preferred_alignment;
505                }
506                false => {
507                    self.0.insert(pos + 1, spec);
508                }
509            },
510            // If we don't have a match, then we're the smallest. Insert at the front.
511            None => self.0.insert(0, spec),
512        }
513    }
514}
515
516/// Errors that can occur when constructing an [`AddressSpace`](AddressSpace)
517#[derive(Debug, Error)]
518pub enum AddressSpaceError {
519    /// The requested address space identifier exceeds our support.
520    #[error("address space identifier is too large ({0} > {})", AddressSpace::MAX)]
521    TooBig(u64),
522}
523
524/// An invariant-preserving newtype for representing the address space of a pointer type.
525#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
526pub struct AddressSpace(u32);
527
528impl TryFrom<u32> for AddressSpace {
529    type Error = AddressSpaceError;
530    fn try_from(value: u32) -> Result<Self, Self::Error> {
531        match value <= AddressSpace::MAX {
532            true => Ok(AddressSpace(value)),
533            false => Err(AddressSpaceError::TooBig(value.into())),
534        }
535    }
536}
537
538impl TryFrom<u64> for AddressSpace {
539    type Error = AddressSpaceError;
540    fn try_from(value: u64) -> Result<Self, Self::Error> {
541        match value <= AddressSpace::MAX.into() {
542            true => Ok(AddressSpace(value as u32)),
543            false => Err(AddressSpaceError::TooBig(value)),
544        }
545    }
546}
547
548impl AddressSpace {
549    /// The maximum address space identifier.
550    pub const MAX: u32 = (1 << 23) - 1;
551}
552
553/// Represents a pointer width (in bits), along with its ABI-mandated and
554/// preferred alignments (which may differ).
555#[non_exhaustive]
556#[derive(Copy, Clone, Debug, Eq, PartialEq)]
557pub struct PointerAlignSpec {
558    /// The address space that this pointer specification is valid in.
559    pub address_space: AddressSpace,
560    /// The ABI-enforced alignment for this pointer.
561    pub abi_alignment: Align,
562    /// The preferred alignment for this pointer.
563    ///
564    /// Like [`TypeAlignSpec`](TypeAlignSpec), this is enforced by construction
565    /// to be no less than the ABI-enforced alignment.
566    pub preferred_alignment: Align,
567    /// The size of this pointer type, in bits.
568    pub pointer_size: u64,
569    /// The size of indexing operations with this pointer type, in bits.
570    pub index_size: u64,
571}
572
573impl PartialOrd for PointerAlignSpec {
574    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
575        Some(self.address_space.cmp(&other.address_space))
576    }
577}
578
579impl Ord for PointerAlignSpec {
580    fn cmp(&self, other: &Self) -> Ordering {
581        self.address_space.cmp(&other.address_space)
582    }
583}
584
585// There's only one default pointer type in LLVM datalayout specifications, so
586// this is fine.
587impl Default for PointerAlignSpec {
588    fn default() -> Self {
589        Self {
590            address_space: AddressSpace::default(),
591            abi_alignment: Align::ALIGN64,
592            preferred_alignment: Align::ALIGN64,
593            pointer_size: 64,
594            index_size: 64,
595        }
596    }
597}
598
599impl FromStr for PointerAlignSpec {
600    type Err = AlignSpecError;
601
602    fn from_str(value: &str) -> Result<Self, Self::Err> {
603        // Every pointer alignment specification looks like this:
604        //     p[n]:<size>:<abi>:<pref>[:idx]
605        // ...where [n] and [:idx] are optional. The absence of [n] implies
606        // `0`, i.e. the default address space.
607
608        if value.is_empty() {
609            return Err(AlignSpecError::Parse(
610                "cannot parse from an empty string".into(),
611            ));
612        }
613
614        let parts: Vec<&str> = value[1..].split(':').collect();
615
616        // We expect no less than 3 parts: `p[n]`, `size`, and `abi`, with
617        // `pref` and `idx` being optional.
618        if parts.len() < 3 {
619            return Err(AlignSpecError::Parse(format!(
620                "pointer align spec has too few parts ({}, expected at least 4)",
621                parts.len()
622            )));
623        }
624
625        let address_space = match parts[0].is_empty() {
626            true => AddressSpace::default(),
627            false => parts[0].parse::<u32>()?.try_into()?,
628        };
629        let pointer_size = parts[1].parse::<u64>()?;
630        let abi = parts[2]
631            .parse::<u64>()
632            .map_err(|e| AlignSpecError::Parse(e.to_string()))
633            .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
634        let pref = parts
635            .get(3)
636            .map(|idx| {
637                idx.parse::<u64>()
638                    .map_err(AlignSpecError::from)
639                    .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
640            })
641            .unwrap_or(Ok(abi))?;
642        let index_size = parts
643            .get(4)
644            .map(|idx| idx.parse::<u64>())
645            .unwrap_or(Ok(pointer_size))?;
646
647        Ok(Self {
648            address_space: address_space,
649            abi_alignment: abi,
650            preferred_alignment: pref,
651            pointer_size: pointer_size,
652            index_size: index_size,
653        })
654    }
655}
656
657impl PointerAlignSpec {
658    /// Create a new `PointerAlignSpec`.
659    pub fn new(
660        address_space: AddressSpace,
661        abi_alignment: Align,
662        preferred_alignment: Align,
663        pointer_size: u64,
664        index_size: u64,
665    ) -> Result<Self, AlignSpecError> {
666        if preferred_alignment < abi_alignment {
667            return Err(AlignSpecError::AlignPref(
668                preferred_alignment,
669                abi_alignment,
670            ));
671        }
672
673        // LLVM doesn't put any constraints on the maximum alignment for pointers
674        // the way it does for other types.
675
676        Ok(Self {
677            address_space,
678            abi_alignment,
679            preferred_alignment,
680            pointer_size,
681            index_size,
682        })
683    }
684}
685
686/// A model for function pointer alignment behavior.
687#[derive(Debug, PartialEq)]
688pub enum FunctionPointerAlign {
689    /// The alignment of function pointers is independent of the alignment
690    /// of functions, and is a multiple of the associated ABI alignment.
691    Independent {
692        /// The ABI-mandated alignment for function pointers.
693        abi_alignment: Align,
694    },
695    /// The alignment of function pointers is a multiple of the explicit
696    /// alignment specified on the function, **and** is a multiple of the
697    /// associated ABI alignment.
698    MultipleOfFunctionAlign {
699        /// The ABI-mandated alignment for function pointers.
700        abi_alignment: Align,
701    },
702}
703
704/// Represents a sorted collection of [`PointerAlignSpec`](PointerAlignSpec)s.
705#[derive(Debug, Eq, PartialEq)]
706pub struct PointerAlignSpecs(Vec<PointerAlignSpec>);
707
708impl Default for PointerAlignSpecs {
709    fn default() -> Self {
710        Self(vec![PointerAlignSpec::default()])
711    }
712}
713
714impl PointerAlignSpecs {
715    /// Update this list of pointer alignment specifications by inserting the given specification
716    /// at the correct location, **or** rewriting an already present specification.
717    pub fn update(&mut self, spec: PointerAlignSpec) {
718        // Find the position of the rightmost spec that's less than or equal to
719        // the spec that we're inserting.
720        let pos = self.0.iter().rposition(|&other| other <= spec);
721        match pos {
722            // If we have a match, then we need to either insert or update
723            // depending on whether our match is the same spec as us.
724            // Panic safety: `pos` is a valid index returned above.
725            Some(pos) => match self.0[pos] == spec {
726                true => {
727                    // Unwrap safety: `pos` is a valid index returned above.
728                    #[allow(clippy::unwrap_used)]
729                    let mut other = self.0.get_mut(pos).unwrap();
730
731                    other.abi_alignment = spec.abi_alignment;
732                    other.preferred_alignment = spec.preferred_alignment;
733                }
734                false => {
735                    self.0.insert(pos + 1, spec);
736                }
737            },
738            // If we don't have a match, then we're the smallest. Insert at the front.
739            None => self.0.insert(0, spec),
740        }
741    }
742}
743
744#[cfg(test)]
745mod tests {
746    use super::*;
747
748    #[test]
749    fn test_align_constants() {
750        assert_eq!(Align::ALIGN8.byte_align(), 1);
751        assert_eq!(Align::ALIGN16.byte_align(), 2);
752        assert_eq!(Align::ALIGN32.byte_align(), 4);
753        assert_eq!(Align::ALIGN64.byte_align(), 8);
754        assert_eq!(Align::ALIGN128.byte_align(), 16);
755    }
756
757    #[test]
758    fn test_align_is_pow2() {
759        assert!(Align::is_pow2(1));
760        assert!(Align::is_pow2(2));
761        assert!(Align::is_pow2(4));
762        assert!(Align::is_pow2(8));
763        assert!(Align::is_pow2(16));
764        assert!(Align::is_pow2(32));
765        assert!(Align::is_pow2(64));
766
767        assert!(!Align::is_pow2(3));
768        assert!(!Align::is_pow2(6));
769        assert!(!Align::is_pow2(12));
770        assert!(!Align::is_pow2(65));
771    }
772
773    #[test]
774    fn test_align_compares() {
775        assert_eq!(Align::from_shift(1).unwrap(), Align::from_shift(1).unwrap());
776        assert!(Align::from_shift(1).unwrap() < Align::from_shift(2).unwrap());
777        assert!(Align::from_shift(1).unwrap() <= Align::from_shift(2).unwrap());
778        assert!(Align::from_shift(2).unwrap() > Align::from_shift(1).unwrap());
779        assert!(Align::from_shift(2).unwrap() >= Align::from_shift(1).unwrap());
780    }
781
782    #[test]
783    fn test_align_log2() {
784        assert_eq!(Align::log2(1), 0);
785        assert_eq!(Align::log2(2), 1);
786        assert_eq!(Align::log2(4), 2);
787        assert_eq!(Align::log2(8), 3);
788        assert_eq!(Align::log2(16), 4);
789        assert_eq!(Align::log2(32), 5);
790        assert_eq!(Align::log2(64), 6);
791
792        // Our internal log2 is a flooring log2.
793        assert_eq!(Align::log2(65), 6);
794    }
795
796    #[test]
797    fn test_align_basic() {
798        for (s, ba) in &[(0, 1), (1, 2), (2, 4), (3, 8), (4, 16), (5, 32), (6, 64)] {
799            let align = Align(*s);
800
801            assert_eq!(align.shift(), *s);
802            assert_eq!(align.byte_align(), *ba);
803            assert_eq!(align.bit_align(), (*ba) * 8);
804        }
805    }
806
807    #[test]
808    fn test_align_from_byte_align() {
809        assert_eq!(Align::from_byte_align(1).unwrap().shift(), 0);
810        assert_eq!(Align::from_byte_align(2).unwrap().shift(), 1);
811        assert_eq!(Align::from_byte_align(4).unwrap().shift(), 2);
812        assert_eq!(Align::from_byte_align(8).unwrap().shift(), 3);
813        assert_eq!(Align::from_byte_align(16).unwrap().shift(), 4);
814        assert_eq!(Align::from_byte_align(32).unwrap().shift(), 5);
815        assert_eq!(Align::from_byte_align(64).unwrap().shift(), 6);
816        assert_eq!(Align::from_byte_align(128).unwrap().shift(), 7);
817
818        assert!(Align::from_byte_align(0).is_err());
819        assert!(Align::from_byte_align(3).is_err());
820        assert!(Align::from_byte_align(7).is_err());
821        assert!(Align::from_byte_align(22).is_err());
822        assert!(Align::from_byte_align(24).is_err());
823    }
824
825    #[test]
826    fn test_align_from_bit_align() {
827        assert_eq!(Align::from_bit_align(8).unwrap().shift(), 0);
828        assert_eq!(Align::from_bit_align(16).unwrap().shift(), 1);
829        assert_eq!(Align::from_bit_align(32).unwrap().shift(), 2);
830        assert_eq!(Align::from_bit_align(64).unwrap().shift(), 3);
831        assert_eq!(Align::from_bit_align(128).unwrap().shift(), 4);
832        assert_eq!(Align::from_bit_align(256).unwrap().shift(), 5);
833        assert_eq!(Align::from_bit_align(512).unwrap().shift(), 6);
834        assert_eq!(Align::from_bit_align(1024).unwrap().shift(), 7);
835
836        assert!(Align::from_bit_align(0).is_err());
837        assert!(Align::from_bit_align(1).is_err());
838        assert!(Align::from_bit_align(7).is_err());
839        assert!(Align::from_bit_align(9).is_err());
840        assert!(Align::from_bit_align(24).is_err());
841        assert!(Align::from_bit_align(33).is_err());
842    }
843
844    #[test]
845    fn test_aligned_type_width() {
846        for i in 1..(1 << 15) {
847            assert!(AlignedTypeWidth::try_from(i).is_ok());
848        }
849
850        assert!(AlignedTypeWidth::try_from(0).is_err());
851        assert!(AlignedTypeWidth::try_from(u32::MAX).is_err());
852    }
853
854    #[test]
855    fn test_aligned_type_ordering() {
856        assert!(
857            AlignedType::Integer(AlignedTypeWidth(1)) == AlignedType::Integer(AlignedTypeWidth(1))
858        );
859        assert!(
860            AlignedType::Vector(AlignedTypeWidth(1)) == AlignedType::Vector(AlignedTypeWidth(1))
861        );
862        assert!(AlignedType::Float(AlignedTypeWidth(1)) == AlignedType::Float(AlignedTypeWidth(1)));
863
864        for i in 2..(1 << 15) {
865            assert!(
866                AlignedType::Integer(AlignedTypeWidth(i))
867                    < AlignedType::Vector(AlignedTypeWidth(i))
868            );
869            assert!(
870                AlignedType::Integer(AlignedTypeWidth(i))
871                    <= AlignedType::Vector(AlignedTypeWidth(i))
872            );
873
874            assert!(
875                AlignedType::Integer(AlignedTypeWidth(i + 1))
876                    < AlignedType::Vector(AlignedTypeWidth(i - 1))
877            );
878            assert!(
879                AlignedType::Integer(AlignedTypeWidth(i + 1))
880                    <= AlignedType::Vector(AlignedTypeWidth(i - 1))
881            );
882
883            assert!(
884                AlignedType::Integer(AlignedTypeWidth(i)) > AlignedType::Float(AlignedTypeWidth(i))
885            );
886            assert!(
887                AlignedType::Integer(AlignedTypeWidth(i))
888                    >= AlignedType::Float(AlignedTypeWidth(i))
889            );
890
891            assert!(
892                AlignedType::Integer(AlignedTypeWidth(i + 1))
893                    > AlignedType::Float(AlignedTypeWidth(i - 1))
894            );
895            assert!(
896                AlignedType::Integer(AlignedTypeWidth(i + 1))
897                    >= AlignedType::Float(AlignedTypeWidth(i - 1))
898            );
899
900            assert!(AlignedType::Integer(AlignedTypeWidth(i)) > AlignedType::Aggregate);
901            assert!(AlignedType::Integer(AlignedTypeWidth(i)) >= AlignedType::Aggregate);
902        }
903
904        assert!(AlignedType::Aggregate == AlignedType::Aggregate);
905    }
906
907    #[test]
908    fn test_type_align_spec() {
909        // Normal cases.
910        assert!(TypeAlignSpec::new(
911            AlignedType::Integer(AlignedTypeWidth(64)),
912            Align::ALIGN64,
913            Align::ALIGN64
914        )
915        .is_ok());
916        assert!(TypeAlignSpec::new(
917            AlignedType::Integer(AlignedTypeWidth(64)),
918            Align::ALIGN64,
919            Align::ALIGN128
920        )
921        .is_ok());
922        assert!(TypeAlignSpec::new(
923            AlignedType::Float(AlignedTypeWidth(32)),
924            Align::ALIGN32,
925            Align::ALIGN32
926        )
927        .is_ok());
928        assert!(TypeAlignSpec::new(
929            AlignedType::Float(AlignedTypeWidth(32)),
930            Align::ALIGN32,
931            Align::ALIGN64
932        )
933        .is_ok());
934
935        // Can't create with an undersized preferred alignment.
936        assert_eq!(
937            TypeAlignSpec::new(
938                AlignedType::Integer(AlignedTypeWidth(8)),
939                Align(2),
940                Align(1)
941            )
942            .unwrap_err()
943            .to_string(),
944            "impossible preferred alignment: 2 must be >= 4"
945        );
946
947        // Can't create with an oversized ABI alignment.
948        assert_eq!(
949            TypeAlignSpec::new(
950                AlignedType::Integer(AlignedTypeWidth(8)),
951                Align(16),
952                Align(16)
953            )
954            .unwrap_err()
955            .to_string(),
956            "impossible ABI alignment for type: 65536 > 32768"
957        );
958    }
959
960    #[test]
961    fn test_type_align_spec_equality() {
962        // Two "different" specs with the same type (+ width) compare as equal.
963        let spec1 =
964            TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap();
965
966        let spec2 =
967            TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN32).unwrap();
968
969        assert_eq!(spec1, spec2);
970    }
971
972    #[test]
973    fn test_type_align_specs_default_sorted() {
974        let specs1 = TypeAlignSpecs::default();
975        let mut specs2 = TypeAlignSpecs::default();
976        specs2.0.sort();
977
978        assert_eq!(specs1, specs2);
979    }
980
981    #[test]
982    fn test_type_align_specs_update() {
983        {
984            // Trivial insertion works.
985            let mut specs = TypeAlignSpecs(vec![]);
986            specs.update(
987                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
988            );
989
990            assert_eq!(specs.0.len(), 1);
991        }
992
993        {
994            // Trivial updating works.
995            let mut specs = TypeAlignSpecs(vec![]);
996            specs.update(
997                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
998            );
999            specs.update(
1000                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN32).unwrap(),
1001            );
1002
1003            assert_eq!(specs.0.len(), 1);
1004        }
1005
1006        {
1007            // Ordered insertion (append) works.
1008            let mut specs = TypeAlignSpecs(vec![]);
1009            specs.update(
1010                TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1011            );
1012            specs.update(
1013                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1014            );
1015
1016            let copy = {
1017                let mut copy = specs.0.clone();
1018                copy.sort();
1019                TypeAlignSpecs(copy)
1020            };
1021
1022            assert_eq!(specs.0.len(), 2);
1023            assert_eq!(specs, copy);
1024        }
1025
1026        {
1027            // Ordered insertion (prepend) works.
1028            let mut specs = TypeAlignSpecs(vec![]);
1029            specs.update(
1030                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1031            );
1032            specs.update(
1033                TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1034            );
1035
1036            let copy = {
1037                let mut copy = specs.0.clone();
1038                copy.sort();
1039                TypeAlignSpecs(copy)
1040            };
1041
1042            assert_eq!(specs.0.len(), 2);
1043            assert_eq!(specs, copy);
1044        }
1045
1046        {
1047            // Ordered insertion (in the middle) works.
1048            let mut specs = TypeAlignSpecs(vec![]);
1049            specs.update(
1050                TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1051            );
1052            specs.update(
1053                TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1054            );
1055            specs.update(
1056                TypeAlignSpec::new(AlignedType::FLOAT16, Align::ALIGN16, Align::ALIGN16).unwrap(),
1057            );
1058
1059            let copy = {
1060                let mut copy = specs.0.clone();
1061                copy.sort();
1062                TypeAlignSpecs(copy)
1063            };
1064
1065            assert_eq!(specs.0.len(), 3);
1066            assert_eq!(specs, copy);
1067        }
1068    }
1069
1070    #[test]
1071    fn test_type_align_spec_parse() {
1072        {
1073            let spec = "i64:64:64".parse::<TypeAlignSpec>().unwrap();
1074
1075            assert_eq!(
1076                spec.aligned_type,
1077                AlignedType::Integer(AlignedTypeWidth::WIDTH64)
1078            );
1079            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1080            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1081        }
1082
1083        {
1084            let spec = "i32:32:64".parse::<TypeAlignSpec>().unwrap();
1085
1086            assert_eq!(
1087                spec.aligned_type,
1088                AlignedType::Integer(AlignedTypeWidth::WIDTH32)
1089            );
1090            assert_eq!(spec.abi_alignment, Align::ALIGN32);
1091            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1092        }
1093
1094        {
1095            let spec = "a:32:64".parse::<TypeAlignSpec>().unwrap();
1096
1097            assert_eq!(spec.aligned_type, AlignedType::Aggregate);
1098            assert_eq!(spec.abi_alignment, Align::ALIGN32);
1099            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1100        }
1101
1102        {
1103            let spec = "a:32".parse::<TypeAlignSpec>().unwrap();
1104
1105            assert_eq!(spec.aligned_type, AlignedType::Aggregate);
1106            assert_eq!(spec.abi_alignment, Align::ALIGN32);
1107            assert_eq!(spec.preferred_alignment, Align::ALIGN32);
1108        }
1109    }
1110
1111    #[test]
1112    fn test_pointer_align_spec_parse() {
1113        {
1114            let spec = "p:64:64:64".parse::<PointerAlignSpec>().unwrap();
1115
1116            assert_eq!(spec.address_space, AddressSpace::default());
1117            assert_eq!(spec.pointer_size, 64);
1118            assert_eq!(spec.index_size, 64);
1119            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1120            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1121        }
1122
1123        {
1124            let spec = "p0:64:64:64".parse::<PointerAlignSpec>().unwrap();
1125
1126            assert_eq!(spec.address_space, AddressSpace::default());
1127            assert_eq!(spec.pointer_size, 64);
1128            assert_eq!(spec.index_size, 64);
1129            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1130            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1131        }
1132
1133        {
1134            let spec = "p:64:64:64:64".parse::<PointerAlignSpec>().unwrap();
1135
1136            assert_eq!(spec.address_space, AddressSpace::default());
1137            assert_eq!(spec.pointer_size, 64);
1138            assert_eq!(spec.index_size, 64);
1139            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1140            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1141        }
1142
1143        {
1144            let spec = "p:64:64:64:32".parse::<PointerAlignSpec>().unwrap();
1145
1146            assert_eq!(spec.address_space, AddressSpace::default());
1147            assert_eq!(spec.pointer_size, 64);
1148            assert_eq!(spec.index_size, 32);
1149            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1150            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1151        }
1152
1153        {
1154            let spec = "p1:64:64:64".parse::<PointerAlignSpec>().unwrap();
1155
1156            assert_eq!(spec.address_space, AddressSpace(1));
1157            assert_eq!(spec.pointer_size, 64);
1158            assert_eq!(spec.index_size, 64);
1159            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1160            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1161        }
1162
1163        {
1164            let spec = "p1:64:64".parse::<PointerAlignSpec>().unwrap();
1165
1166            assert_eq!(spec.address_space, AddressSpace(1));
1167            assert_eq!(spec.pointer_size, 64);
1168            assert_eq!(spec.index_size, 64);
1169            assert_eq!(spec.abi_alignment, Align::ALIGN64);
1170            assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1171        }
1172    }
1173
1174    #[test]
1175    fn test_address_space() {
1176        assert!(AddressSpace::try_from(0_u32).is_ok());
1177        assert!(AddressSpace::try_from(1_u32).is_ok());
1178        assert!(AddressSpace::try_from(AddressSpace::MAX).is_ok());
1179
1180        assert!(AddressSpace::try_from(AddressSpace::MAX + 1).is_err());
1181    }
1182
1183    #[test]
1184    fn test_address_space_ordering() {
1185        assert!(AddressSpace(0) < AddressSpace(1));
1186        assert!(AddressSpace(0) <= AddressSpace(1));
1187        assert!(AddressSpace(0) == AddressSpace(0));
1188    }
1189}