inkwell/types/
mod.rs

1//! A type is a classification which determines how data is used.
2
3#[deny(missing_docs)]
4mod array_type;
5mod enums;
6#[deny(missing_docs)]
7mod float_type;
8#[deny(missing_docs)]
9mod fn_type;
10#[deny(missing_docs)]
11mod int_type;
12#[deny(missing_docs)]
13mod metadata_type;
14#[deny(missing_docs)]
15mod ptr_type;
16#[deny(missing_docs)]
17mod scalable_vec_type;
18#[deny(missing_docs)]
19mod struct_type;
20#[deny(missing_docs)]
21mod traits;
22#[deny(missing_docs)]
23mod vec_type;
24#[deny(missing_docs)]
25mod void_type;
26
27pub use crate::types::array_type::ArrayType;
28pub use crate::types::enums::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum};
29pub use crate::types::float_type::FloatType;
30pub use crate::types::fn_type::FunctionType;
31pub use crate::types::int_type::{IntType, StringRadix};
32pub use crate::types::metadata_type::MetadataType;
33pub use crate::types::ptr_type::PointerType;
34pub use crate::types::scalable_vec_type::ScalableVectorType;
35pub use crate::types::struct_type::FieldTypesIter;
36pub use crate::types::struct_type::StructType;
37pub use crate::types::traits::{AnyType, AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType};
38pub use crate::types::vec_type::VectorType;
39pub use crate::types::void_type::VoidType;
40
41#[llvm_versions(12..)]
42use llvm_sys::core::LLVMScalableVectorType;
43
44#[llvm_versions(12..)]
45use llvm_sys::core::LLVMGetPoison;
46
47#[allow(deprecated)]
48use llvm_sys::core::LLVMArrayType;
49use llvm_sys::core::{
50    LLVMAlignOf, LLVMConstNull, LLVMConstPointerNull, LLVMFunctionType, LLVMGetElementType, LLVMGetTypeContext,
51    LLVMGetTypeKind, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString, LLVMSizeOf, LLVMTypeIsSized, LLVMVectorType,
52};
53use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
54use llvm_sys::LLVMTypeKind;
55#[cfg(feature = "experimental")]
56use static_alloc::Bump;
57
58use std::fmt;
59use std::marker::PhantomData;
60
61use crate::context::ContextRef;
62use crate::support::LLVMString;
63use crate::values::IntValue;
64use crate::AddressSpace;
65
66// Worth noting that types seem to be singletons. At the very least, primitives are.
67// Though this is likely only true per thread since LLVM claims to not be very thread-safe.
68#[derive(PartialEq, Eq, Clone, Copy)]
69struct Type<'ctx> {
70    ty: LLVMTypeRef,
71    _marker: PhantomData<&'ctx ()>,
72}
73
74impl<'ctx> Type<'ctx> {
75    unsafe fn new(ty: LLVMTypeRef) -> Self {
76        assert!(!ty.is_null());
77
78        Type {
79            ty,
80            _marker: PhantomData,
81        }
82    }
83
84    fn const_zero(self) -> LLVMValueRef {
85        unsafe {
86            match LLVMGetTypeKind(self.ty) {
87                LLVMTypeKind::LLVMMetadataTypeKind => LLVMConstPointerNull(self.ty),
88                _ => LLVMConstNull(self.ty),
89            }
90        }
91    }
92
93    fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {
94        unsafe { PointerType::new(LLVMPointerType(self.ty, address_space.0)) }
95    }
96
97    fn vec_type(self, size: u32) -> VectorType<'ctx> {
98        assert!(size != 0, "Vectors of size zero are not allowed.");
99        // -- https://llvm.org/docs/LangRef.html#vector-type
100
101        unsafe { VectorType::new(LLVMVectorType(self.ty, size)) }
102    }
103
104    #[llvm_versions(12..)]
105    fn scalable_vec_type(self, size: u32) -> ScalableVectorType<'ctx> {
106        assert!(size != 0, "Vectors of size zero are not allowed.");
107        // -- https://llvm.org/docs/LangRef.html#vector-type
108
109        unsafe { ScalableVectorType::new(LLVMScalableVectorType(self.ty, size)) }
110    }
111
112    #[cfg(not(feature = "experimental"))]
113    fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
114        let mut param_types: Vec<LLVMTypeRef> = param_types.iter().map(|val| val.as_type_ref()).collect();
115        unsafe {
116            FunctionType::new(LLVMFunctionType(
117                self.ty,
118                param_types.as_mut_ptr(),
119                param_types.len() as u32,
120                is_var_args as i32,
121            ))
122        }
123    }
124
125    #[cfg(feature = "experimental")]
126    fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
127        let pool: Bump<[usize; 16]> = Bump::uninit();
128        let mut pool_start = None;
129
130        for (i, param_type) in param_types.iter().enumerate() {
131            let addr = pool.leak(param_type.as_type_ref()).expect("Found more than 16 params");
132
133            if i == 0 {
134                pool_start = Some(addr as *mut _);
135            }
136        }
137
138        unsafe {
139            FunctionType::new(LLVMFunctionType(
140                self.ty,
141                pool_start.unwrap_or(std::ptr::null_mut()),
142                param_types.len() as u32,
143                is_var_args as i32,
144            ))
145        }
146    }
147
148    #[allow(deprecated)]
149    fn array_type(self, size: u32) -> ArrayType<'ctx> {
150        unsafe { ArrayType::new(LLVMArrayType(self.ty, size)) }
151    }
152
153    fn get_undef(self) -> LLVMValueRef {
154        unsafe { LLVMGetUndef(self.ty) }
155    }
156
157    #[llvm_versions(12..)]
158    fn get_poison(&self) -> LLVMValueRef {
159        unsafe { LLVMGetPoison(self.ty) }
160    }
161
162    fn get_alignment(self) -> IntValue<'ctx> {
163        unsafe { IntValue::new(LLVMAlignOf(self.ty)) }
164    }
165
166    fn get_context(self) -> ContextRef<'ctx> {
167        unsafe { ContextRef::new(LLVMGetTypeContext(self.ty)) }
168    }
169
170    // REVIEW: This should be known at compile time, maybe as a const fn?
171    // On an enum or trait, this would not be known at compile time (unless
172    // enum has only sized types for example)
173    fn is_sized(self) -> bool {
174        unsafe { LLVMTypeIsSized(self.ty) == 1 }
175    }
176
177    fn size_of(self) -> Option<IntValue<'ctx>> {
178        if !self.is_sized() {
179            return None;
180        }
181
182        unsafe { Some(IntValue::new(LLVMSizeOf(self.ty))) }
183    }
184
185    fn print_to_string(self) -> LLVMString {
186        unsafe { LLVMString::new(LLVMPrintTypeToString(self.ty)) }
187    }
188
189    pub fn get_element_type(self) -> AnyTypeEnum<'ctx> {
190        unsafe { AnyTypeEnum::new(LLVMGetElementType(self.ty)) }
191    }
192}
193
194impl fmt::Debug for Type<'_> {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        let llvm_type = self.print_to_string();
197
198        f.debug_struct("Type")
199            .field("address", &self.ty)
200            .field("llvm_type", &llvm_type)
201            .finish()
202    }
203}