llvm_support/
ty.rs

1//! Structures for managing LLVM types.
2
3use std::convert::TryFrom;
4
5use thiserror::Error;
6
7use crate::AddressSpace;
8
9/// The IDs of types known to LLVM.
10///
11/// These are not fully unique: all integer types share the `Integer` type ID,
12/// and similarly for pointers, arrays, etc.
13// TODO(ww): Perhaps use arbitrary enum discriminants here when they're stabilized.
14// See: https://github.com/rust-lang/rfcs/pull/2363
15#[repr(u64)]
16pub enum TypeId {
17    /// 16-bit floating-points.
18    Half = 0,
19    /// 16-bit floating-points (7-bit significand).
20    BFloat,
21    /// 32-bit floating-points.
22    Float,
23    /// 64-bit floating-points.
24    Double,
25    /// 80-bit floating-points (x87).
26    X86Fp80,
27    /// 128-bit floating-points (112-bit significand).
28    Fp128,
29    /// 128-bit floating-points (two 64-bits, PowerPC).
30    PpcFp128,
31    /// The void type (a type with no size).
32    Void,
33    /// Labels.
34    Label,
35    /// Metadata.
36    Metadata,
37    /// MMX vectors (64 bits, x86).
38    X86Mmx,
39    /// AMX vectors (8192 bits, x86).
40    X86Amx,
41    /// Tokens.
42    Token,
43    /// Arbitrary bit-width integers.
44    Integer,
45    /// Functions.
46    Function,
47    /// Pointers.
48    Pointer,
49    /// Structures.
50    Struct,
51    /// Arrays.
52    Array,
53    /// Fixed-width SIMD vectors.
54    FixedVector,
55    /// Scalable SIMD vectors.
56    ScalableVector,
57}
58
59/// A representation of LLVM's types.
60///
61/// See [`TypeId`](TypeId) for documentation of each variant.
62#[allow(missing_docs)]
63#[derive(Clone, Debug, PartialEq)]
64pub enum Type {
65    Half,
66    BFloat,
67    Float,
68    Double,
69    Metadata,
70    X86Fp80,
71    Fp128,
72    PpcFp128,
73    Void,
74    Label,
75    X86Mmx,
76    X86Amx,
77    Token,
78    Integer(IntegerType),
79    Function(FunctionType),
80    Pointer(PointerType),
81    OpaquePointer(AddressSpace),
82    Struct(StructType),
83    Array(ArrayType),
84    FixedVector(VectorType),
85    ScalableVector(VectorType),
86}
87
88impl Type {
89    /// Returns whether this type is one of the floating point types.
90    ///
91    /// ```rust
92    /// use llvm_support::Type;
93    ///
94    /// assert!(Type::BFloat.is_floating());
95    /// assert!(Type::Float.is_floating());
96    /// assert!(Type::Double.is_floating());
97    /// assert!(Type::X86Fp80.is_floating());
98    /// assert!(Type::Fp128.is_floating());
99    /// assert!(Type::PpcFp128.is_floating());
100    /// assert!(!Type::Metadata.is_floating());
101    /// ```
102    pub fn is_floating(&self) -> bool {
103        matches!(
104            self,
105            Type::Half
106                | Type::BFloat
107                | Type::Float
108                | Type::Double
109                | Type::X86Fp80
110                | Type::Fp128
111                | Type::PpcFp128
112        )
113    }
114
115    /// Returns whether this type is a valid "pointee" type, i.e. suitable as the inner type
116    /// for a pointer type.
117    pub fn is_pointee(&self) -> bool {
118        !matches!(
119            self,
120            Type::Void | Type::Label | Type::Metadata | Type::Token | Type::X86Amx
121        )
122    }
123
124    /// Returns whether this type is a valid array element type, i.e. is suitable as the inner type
125    /// for an array type.
126    pub fn is_array_element(&self) -> bool {
127        !matches!(
128            self,
129            Type::Void
130                | Type::Label
131                | Type::Metadata
132                | Type::Function(_)
133                | Type::Token
134                | Type::X86Amx
135                | Type::ScalableVector(_)
136        )
137    }
138
139    /// Returns whether this type is a valid structure element type, i.e. is suitable as a field
140    /// type within a structure type.
141    pub fn is_struct_element(&self) -> bool {
142        !matches!(
143            self,
144            Type::Void | Type::Label | Type::Metadata | Type::Function(_) | Type::Token
145        )
146    }
147
148    /// Returns whether this type is a valid vector element type, i.e. is suitable as the inner
149    /// type for a vector type.
150    ///
151    /// ```rust
152    /// use llvm_support::{AddressSpace, Type};
153    ///
154    /// assert!(Type::Float.is_vector_element());
155    /// assert!(Type::new_integer(32).unwrap().is_vector_element());
156    /// assert!(
157    ///     Type::new_pointer(Type::new_integer(8).unwrap(), AddressSpace::default())
158    ///     .unwrap()
159    ///     .is_vector_element()
160    /// );
161    /// assert!(!Type::Metadata.is_vector_element());
162    /// ```
163    pub fn is_vector_element(&self) -> bool {
164        self.is_floating() || matches!(self, Type::Integer(_) | Type::Pointer(_))
165    }
166
167    /// Returns whether this type is "first class", i.e. is a valid type for an LLVM value.
168    fn is_first_class(&self) -> bool {
169        !matches!(self, Type::Function(_) | Type::Void)
170    }
171
172    /// Returns whether this type is a valid argument type, i.e. is suitable as an argument
173    /// within a function type.
174    ///
175    /// ```rust
176    /// use llvm_support::Type;
177    ///
178    /// assert!(Type::Float.is_argument());
179    /// assert!(!Type::Void.is_argument());
180    /// ```
181    pub fn is_argument(&self) -> bool {
182        self.is_first_class()
183    }
184
185    /// Returns whether this type is a valid return type, i.e. is suitable as the return type
186    /// within a function type.
187    pub fn is_return(&self) -> bool {
188        !matches!(self, Type::Function(_) | Type::Label | Type::Metadata)
189    }
190
191    /// Create a new struct type with the given fields.
192    pub fn new_struct(
193        name: Option<String>,
194        fields: Vec<Type>,
195        is_packed: bool,
196    ) -> Result<Self, StructTypeError> {
197        let inner = StructType::new(name, fields, is_packed)?;
198
199        Ok(Type::Struct(inner))
200    }
201
202    /// Create a new integral type from the given bit width.
203    pub fn new_integer(bit_width: u32) -> Result<Self, IntegerTypeError> {
204        let inner = IntegerType::try_from(bit_width)?;
205
206        Ok(Type::Integer(inner))
207    }
208
209    /// Create a new pointer type from the given pointee type and address space.
210    pub fn new_pointer(
211        pointee: Type,
212        address_space: AddressSpace,
213    ) -> Result<Self, PointerTypeError> {
214        let inner = PointerType::new(pointee, address_space)?;
215
216        Ok(Type::Pointer(inner))
217    }
218
219    /// Create a new array type of the given size and element type.
220    pub fn new_array(num_elements: u64, element_type: Type) -> Result<Self, ArrayTypeError> {
221        let inner = ArrayType::new(num_elements, element_type)?;
222
223        Ok(Type::Array(inner))
224    }
225
226    /// Create a new scalable vector type of the given size and element type.
227    pub fn new_scalable_vector(
228        num_elements: u64,
229        element_type: Type,
230    ) -> Result<Self, VectorTypeError> {
231        let inner = VectorType::new(num_elements, element_type)?;
232
233        Ok(Type::ScalableVector(inner))
234    }
235
236    /// Create a new (fixed) vector type of the given size and element type.
237    pub fn new_vector(num_elements: u64, element_type: Type) -> Result<Self, VectorTypeError> {
238        let inner = VectorType::new(num_elements, element_type)?;
239
240        Ok(Type::FixedVector(inner))
241    }
242
243    /// Create a new function type of the given return type, parameter types, and variadic disposition.
244    pub fn new_function(
245        return_type: Type,
246        param_types: Vec<Type>,
247        is_vararg: bool,
248    ) -> Result<Self, FunctionTypeError> {
249        let inner = FunctionType::new(return_type, param_types, is_vararg)?;
250
251        Ok(Type::Function(inner))
252    }
253}
254
255/// Errors that can occur when constructing an [`StructType`](StructType).
256#[derive(Debug, Error)]
257pub enum StructTypeError {
258    /// The requested element type is invalid.
259    #[error("invalid structure element type: {0:?}")]
260    BadElement(Type),
261}
262
263/// Represents a "struct" type.
264#[non_exhaustive]
265#[derive(Clone, Debug, PartialEq)]
266pub struct StructType {
267    /// This structure's name, if is has one.
268    pub name: Option<String>,
269    /// The individual fields of this structure.
270    pub fields: Vec<Type>,
271    /// Whether the fields of this structure are packed.
272    is_packed: bool,
273}
274
275impl StructType {
276    /// Create a new `StructType`.
277    pub fn new(
278        name: Option<String>,
279        fields: Vec<Type>,
280        is_packed: bool,
281    ) -> Result<Self, StructTypeError> {
282        if let Some(bad) = fields.iter().find(|t| !t.is_struct_element()) {
283            Err(StructTypeError::BadElement(bad.clone()))
284        } else {
285            Ok(Self {
286                name,
287                fields,
288                is_packed,
289            })
290        }
291    }
292}
293
294/// Errors that can occur when constructing an [`IntegerType`](IntegerType).
295#[derive(Debug, Error)]
296pub enum IntegerTypeError {
297    /// The requested bit width for this integer type is invalid.
298    #[error(
299        "specified bit width is invalid (not in [{}, {}])",
300        IntegerType::MIN_INT_BITS,
301        IntegerType::MAX_INT_BITS
302    )]
303    BadWidth,
304}
305
306/// Represents a fixed-width integral type.
307///
308/// The validity of the internal width is correct by construction.
309#[non_exhaustive]
310#[derive(Clone, Debug, PartialEq)]
311pub struct IntegerType {
312    /// The width of this integral type, in bits.
313    bit_width: u32,
314}
315
316impl IntegerType {
317    /// The minimum number of bits in a valid integer type.
318    pub const MIN_INT_BITS: u32 = 1;
319    /// The maximum number of bits in a valid integer type.
320    pub const MAX_INT_BITS: u32 = (1 << 24) - 1;
321
322    /// Returns the width of this integral type in bits.
323    pub fn bit_width(&self) -> u32 {
324        self.bit_width
325    }
326
327    /// Returns the width of this integral type in bytes.
328    ///
329    /// The byte width of this type may be larger than the number of bits needed.
330    pub fn byte_width(&self) -> u32 {
331        (self.bit_width + 7) / 8
332    }
333}
334
335impl TryFrom<u32> for IntegerType {
336    type Error = IntegerTypeError;
337
338    fn try_from(value: u32) -> Result<Self, Self::Error> {
339        if (IntegerType::MIN_INT_BITS..=IntegerType::MAX_INT_BITS).contains(&value) {
340            Ok(Self { bit_width: value })
341        } else {
342            Err(Self::Error::BadWidth)
343        }
344    }
345}
346
347/// Errors that can occur when constructing an [`PointerType`](PointerType).
348#[derive(Debug, Error)]
349pub enum PointerTypeError {
350    /// The requested pointee type is invalid.
351    #[error("invalid pointee type: {0:?}")]
352    BadPointee(Type),
353}
354
355/// Represents a pointer type in some address space.
356///
357/// The validity of the internal pointee type is correct by construction.
358#[non_exhaustive]
359#[derive(Clone, Debug, PartialEq)]
360pub struct PointerType {
361    pointee: Box<Type>,
362    address_space: AddressSpace,
363}
364
365impl PointerType {
366    /// Create a new `PointerType`.
367    pub fn new(pointee: Type, address_space: AddressSpace) -> Result<Self, PointerTypeError> {
368        if pointee.is_pointee() {
369            Ok(Self {
370                pointee: Box::new(pointee),
371                address_space,
372            })
373        } else {
374            Err(PointerTypeError::BadPointee(pointee))
375        }
376    }
377
378    /// Return a reference to the pointed-to type.
379    pub fn pointee(&self) -> &Type {
380        self.pointee.as_ref()
381    }
382}
383
384/// Errors that can occur when constructing an [`ArrayType`](ArrayType).
385#[derive(Debug, Error)]
386pub enum ArrayTypeError {
387    /// The requested element type is invalid.
388    #[error("invalid array element type: {0:?}")]
389    BadElement(Type),
390}
391
392/// Represents an array type.
393#[non_exhaustive]
394#[derive(Clone, Debug, PartialEq)]
395pub struct ArrayType {
396    num_elements: u64,
397    element_type: Box<Type>,
398}
399
400impl ArrayType {
401    /// Create a new `ArrayType`.
402    pub fn new(num_elements: u64, element_type: Type) -> Result<Self, ArrayTypeError> {
403        if element_type.is_array_element() {
404            Ok(Self {
405                num_elements,
406                element_type: Box::new(element_type),
407            })
408        } else {
409            Err(ArrayTypeError::BadElement(element_type))
410        }
411    }
412
413    /// Return a reference to the inner element type.
414    pub fn element(&self) -> &Type {
415        self.element_type.as_ref()
416    }
417}
418
419/// Errors that can occur when constructing a [`VectorType`](VectorType).
420#[derive(Debug, Error)]
421pub enum VectorTypeError {
422    /// The requested element type is invalid.
423    #[error("invalid vector element type: {0:?}")]
424    BadElement(Type),
425}
426
427/// Represents an vector type.
428///
429/// This vector may be fixed or scaled; which one is determined by its surrounding
430/// [`Type`](Type) variant.
431#[non_exhaustive]
432#[derive(Clone, Debug, PartialEq)]
433pub struct VectorType {
434    num_elements: u64,
435    element_type: Box<Type>,
436}
437
438impl VectorType {
439    /// Create a new `VectorType`.
440    pub fn new(num_elements: u64, element_type: Type) -> Result<Self, VectorTypeError> {
441        if element_type.is_vector_element() {
442            Ok(Self {
443                num_elements,
444                element_type: Box::new(element_type),
445            })
446        } else {
447            Err(VectorTypeError::BadElement(element_type))
448        }
449    }
450
451    /// Return a reference to the inner element type.
452    pub fn element(&self) -> &Type {
453        self.element_type.as_ref()
454    }
455}
456
457/// Errors that can occur when constructing a [`FunctionType`](FunctionType).
458#[derive(Debug, Error)]
459pub enum FunctionTypeError {
460    /// The requested return type is invalid.
461    #[error("invalid function return type: {0:?}")]
462    BadReturn(Type),
463    /// The requested parameter type is invalid.
464    #[error("invalid function parameter type: {0:?}")]
465    BadParameter(Type),
466}
467
468/// Represents an function type.
469#[non_exhaustive]
470#[derive(Clone, Debug, PartialEq)]
471pub struct FunctionType {
472    return_type: Box<Type>,
473    param_types: Vec<Type>,
474    is_vararg: bool,
475}
476
477impl FunctionType {
478    /// Create a new `FunctionType`.
479    pub fn new(
480        return_type: Type,
481        param_types: Vec<Type>,
482        is_vararg: bool,
483    ) -> Result<Self, FunctionTypeError> {
484        if !return_type.is_return() {
485            Err(FunctionTypeError::BadReturn(return_type))
486        } else if let Some(bad) = param_types.iter().find(|ty| !ty.is_argument()) {
487            Err(FunctionTypeError::BadParameter(bad.clone()))
488        } else {
489            Ok(FunctionType {
490                return_type: Box::new(return_type),
491                param_types,
492                is_vararg,
493            })
494        }
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use super::*;
501
502    #[test]
503    fn test_integer_type() {
504        {
505            // Error cases.
506            assert!(IntegerType::try_from(0).is_err());
507            assert!(IntegerType::try_from(IntegerType::MAX_INT_BITS + 1).is_err());
508        }
509
510        {
511            // Normal cases.
512            let ty = IntegerType::try_from(IntegerType::MIN_INT_BITS).unwrap();
513            assert_eq!(ty.bit_width(), 1);
514            assert_eq!(ty.byte_width(), 1);
515
516            let ty = IntegerType::try_from(IntegerType::MAX_INT_BITS).unwrap();
517            assert_eq!(ty.bit_width(), IntegerType::MAX_INT_BITS);
518            assert_eq!(ty.byte_width(), 2097152);
519
520            let ty = IntegerType::try_from(31).unwrap();
521            assert_eq!(ty.bit_width(), 31);
522            assert_eq!(ty.byte_width(), 4);
523
524            let ty = IntegerType::try_from(32).unwrap();
525            assert_eq!(ty.bit_width(), 32);
526            assert_eq!(ty.byte_width(), 4);
527
528            for i in 1..=8 {
529                let ty = IntegerType::try_from(i).unwrap();
530                assert_eq!(ty.bit_width(), i);
531                assert_eq!(ty.byte_width(), 1);
532            }
533        }
534    }
535
536    #[test]
537    fn test_pointer_type() {
538        {
539            // Error cases.
540            assert!(PointerType::new(Type::Void, AddressSpace::default()).is_err());
541            assert!(PointerType::new(Type::Label, AddressSpace::default()).is_err());
542            assert!(PointerType::new(Type::Metadata, AddressSpace::default()).is_err());
543            assert!(PointerType::new(Type::Token, AddressSpace::default()).is_err());
544            assert!(PointerType::new(Type::X86Amx, AddressSpace::default()).is_err());
545        }
546
547        {
548            // Normal cases.
549            let ty = PointerType::new(Type::Double, AddressSpace::default()).unwrap();
550            assert_eq!(ty.pointee(), &Type::Double);
551
552            let ty =
553                PointerType::new(Type::new_integer(32).unwrap(), AddressSpace::default()).unwrap();
554            assert_eq!(ty.pointee(), &Type::new_integer(32).unwrap());
555        }
556    }
557}