Skip to main content

inkwell/types/
int_type.rs

1use llvm_sys::core::{
2    LLVMConstAllOnes, LLVMConstInt, LLVMConstIntOfArbitraryPrecision, LLVMConstIntOfStringAndSize, LLVMGetIntTypeWidth,
3};
4use llvm_sys::execution_engine::LLVMCreateGenericValueOfInt;
5use llvm_sys::prelude::LLVMTypeRef;
6
7use crate::context::ContextRef;
8use crate::support::LLVMString;
9use crate::types::traits::AsTypeRef;
10#[llvm_versions(12..)]
11use crate::types::ScalableVectorType;
12use crate::types::{ArrayType, FunctionType, PointerType, Type, VectorType};
13use crate::values::{ArrayValue, GenericValue, IntValue};
14use crate::AddressSpace;
15
16use crate::types::enums::BasicMetadataTypeEnum;
17use std::convert::TryFrom;
18use std::fmt::{self, Display};
19
20/// How to interpret a string or digits used to construct an integer constant.
21#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
22pub enum StringRadix {
23    /// Binary 0 or 1
24    Binary = 2,
25    /// Octal 0-7
26    Octal = 8,
27    /// Decimal 0-9
28    Decimal = 10,
29    /// Hexadecimal with upper or lowercase letters up to F.
30    Hexadecimal = 16,
31    /// Alphanumeric, 0-9 and all 26 letters in upper or lowercase.
32    Alphanumeric = 36,
33}
34
35impl TryFrom<u8> for StringRadix {
36    type Error = ();
37
38    fn try_from(value: u8) -> Result<Self, Self::Error> {
39        match value {
40            2 => Ok(StringRadix::Binary),
41            8 => Ok(StringRadix::Octal),
42            10 => Ok(StringRadix::Decimal),
43            16 => Ok(StringRadix::Hexadecimal),
44            36 => Ok(StringRadix::Alphanumeric),
45            _ => Err(()),
46        }
47    }
48}
49
50impl StringRadix {
51    /// Is the string valid for the given radix?
52    pub fn matches_str(&self, slice: &str) -> bool {
53        // drop 1 optional + or -
54        let slice = slice.strip_prefix(|c| c == '+' || c == '-').unwrap_or(slice);
55
56        // there must be at least 1 actual digit
57        if slice.is_empty() {
58            return false;
59        }
60
61        // and all digits must be in the radix' character set
62        slice.chars().all(|c| c.is_digit(*self as u32))
63    }
64}
65
66/// An `IntType` is the type of an integer constant or variable.
67#[derive(Debug, PartialEq, Eq, Clone, Copy)]
68pub struct IntType<'ctx> {
69    int_type: Type<'ctx>,
70}
71
72impl<'ctx> IntType<'ctx> {
73    /// Create `IntType` from [`LLVMTypeRef`]
74    ///
75    /// # Safety
76    /// Undefined behavior, if referenced type isn't int type
77    pub unsafe fn new(int_type: LLVMTypeRef) -> Self {
78        assert!(!int_type.is_null());
79
80        IntType {
81            int_type: Type::new(int_type),
82        }
83    }
84
85    /// Creates an `IntValue` representing a constant value of this `IntType`. It will be automatically assigned this `IntType`'s `Context`.
86    ///
87    /// # Example
88    /// ```no_run
89    /// use inkwell::context::Context;
90    ///
91    /// // Local Context
92    /// let context = Context::create();
93    /// let i32_type = context.i32_type();
94    /// let i32_value = i32_type.const_int(42, false);
95    /// ```
96    // TODOC: Maybe better explain sign extension
97    pub fn const_int(self, value: u64, sign_extend: bool) -> IntValue<'ctx> {
98        unsafe { IntValue::new(LLVMConstInt(self.as_type_ref(), value, sign_extend as i32)) }
99    }
100
101    /// Create an `IntValue` from a string and radix. LLVM provides no error handling here,
102    /// so this may produce unexpected results and should not be relied upon for validation.
103    ///
104    /// # Example
105    ///
106    /// ```no_run
107    /// use std::convert::TryFrom;
108    ///
109    /// use inkwell::context::Context;
110    /// use inkwell::types::StringRadix;
111    /// use inkwell::values::AnyValue;
112    ///
113    /// let context = Context::create();
114    /// let i8_type = context.i8_type();
115    /// let i8_val = i8_type.const_int_from_string("0121", StringRadix::Decimal).unwrap();
116    ///
117    /// assert_eq!(i8_val.print_to_string().to_string(), "i8 121");
118    ///
119    /// let i8_val = i8_type.const_int_from_string("0121", StringRadix::try_from(10).unwrap()).unwrap();
120    ///
121    /// assert_eq!(i8_val.print_to_string().to_string(), "i8 16");
122    ///
123    /// let i8_val = i8_type.const_int_from_string("0121", StringRadix::Binary);
124    /// assert!(i8_val.is_none());
125    ///
126    /// let i8_val = i8_type.const_int_from_string("ABCD", StringRadix::Binary);
127    /// assert!(i8_val.is_none());
128    /// ```
129    pub fn const_int_from_string(self, slice: &str, radix: StringRadix) -> Option<IntValue<'ctx>> {
130        if !radix.matches_str(slice) {
131            return None;
132        }
133
134        unsafe {
135            Some(IntValue::new(LLVMConstIntOfStringAndSize(
136                self.as_type_ref(),
137                slice.as_ptr() as *const ::libc::c_char,
138                slice.len() as u32,
139                radix as u8,
140            )))
141        }
142    }
143
144    /// Create a constant `IntValue` of arbitrary precision.
145    ///
146    /// # Example
147    ///
148    /// ```no_run
149    /// use inkwell::context::Context;
150    ///
151    /// let context = Context::create();
152    /// let i64_type = context.i64_type();
153    /// let i64_val = i64_type.const_int_arbitrary_precision(&[1, 2]);
154    /// ```
155    pub fn const_int_arbitrary_precision(self, words: &[u64]) -> IntValue<'ctx> {
156        unsafe {
157            IntValue::new(LLVMConstIntOfArbitraryPrecision(
158                self.as_type_ref(),
159                words.len() as u32,
160                words.as_ptr(),
161            ))
162        }
163    }
164
165    /// Creates an `IntValue` representing a constant value of all one bits of this `IntType`. It will be automatically assigned this `IntType`'s `Context`.
166    ///
167    /// # Example
168    /// ```no_run
169    /// use inkwell::context::Context;
170    ///
171    /// // Local Context
172    /// let context = Context::create();
173    /// let i32_type = context.i32_type();
174    /// let i32_ptr_value = i32_type.const_all_ones();
175    /// ```
176    pub fn const_all_ones(self) -> IntValue<'ctx> {
177        unsafe { IntValue::new(LLVMConstAllOnes(self.as_type_ref())) }
178    }
179
180    /// Creates a constant zero value of this `IntType`.
181    ///
182    /// # Example
183    ///
184    /// ```no_run
185    /// use inkwell::context::Context;
186    /// use inkwell::values::AnyValue;
187    ///
188    /// let context = Context::create();
189    /// let i8_type = context.i8_type();
190    /// let i8_zero = i8_type.const_zero();
191    ///
192    /// assert_eq!(i8_zero.print_to_string().to_string(), "i8 0");
193    /// ```
194    pub fn const_zero(self) -> IntValue<'ctx> {
195        unsafe { IntValue::new(self.int_type.const_zero()) }
196    }
197
198    /// Creates a `FunctionType` with this `IntType` for its return type.
199    ///
200    /// # Example
201    ///
202    /// ```no_run
203    /// use inkwell::context::Context;
204    ///
205    /// let context = Context::create();
206    /// let i8_type = context.i8_type();
207    /// let fn_type = i8_type.fn_type(&[], false);
208    /// ```
209    pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
210        self.int_type.fn_type(param_types, is_var_args)
211    }
212
213    /// Creates an `ArrayType` with this `IntType` for its element type.
214    ///
215    /// # Example
216    ///
217    /// ```no_run
218    /// use inkwell::context::Context;
219    ///
220    /// let context = Context::create();
221    /// let i8_type = context.i8_type();
222    /// let i8_array_type = i8_type.array_type(3);
223    ///
224    /// assert_eq!(i8_array_type.len(), 3);
225    /// assert_eq!(i8_array_type.get_element_type().into_int_type(), i8_type);
226    /// ```
227    pub fn array_type(self, size: u32) -> ArrayType<'ctx> {
228        self.int_type.array_type(size)
229    }
230
231    /// Creates a `VectorType` with this `IntType` for its element type.
232    ///
233    /// # Example
234    ///
235    /// ```no_run
236    /// use inkwell::context::Context;
237    ///
238    /// let context = Context::create();
239    /// let i8_type = context.i8_type();
240    /// let i8_vector_type = i8_type.vec_type(3);
241    ///
242    /// assert_eq!(i8_vector_type.get_size(), 3);
243    /// assert_eq!(i8_vector_type.get_element_type().into_int_type(), i8_type);
244    /// ```
245    pub fn vec_type(self, size: u32) -> VectorType<'ctx> {
246        self.int_type.vec_type(size)
247    }
248
249    /// Creates a `ScalableVectorType` with this `IntType` for its element type.
250    ///
251    /// # Example
252    ///
253    /// ```no_run
254    /// use inkwell::context::Context;
255    ///
256    /// let context = Context::create();
257    /// let i8_type = context.i8_type();
258    /// let i8_scalable_vector_type = i8_type.scalable_vec_type(3);
259    ///
260    /// assert_eq!(i8_scalable_vector_type.get_size(), 3);
261    /// assert_eq!(i8_scalable_vector_type.get_element_type().into_int_type(), i8_type);
262    /// ```
263    #[llvm_versions(12..)]
264    pub fn scalable_vec_type(self, size: u32) -> ScalableVectorType<'ctx> {
265        self.int_type.scalable_vec_type(size)
266    }
267
268    /// Gets a reference to the `Context` this `IntType` was created in.
269    ///
270    /// # Example
271    ///
272    /// ```no_run
273    /// use inkwell::context::Context;
274    ///
275    /// let context = Context::create();
276    /// let i8_type = context.i8_type();
277    ///
278    /// assert_eq!(i8_type.get_context(), context);
279    /// ```
280    pub fn get_context(self) -> ContextRef<'ctx> {
281        self.int_type.get_context()
282    }
283
284    /// Gets the size of this `IntType`. Value may vary depending on the target architecture.
285    ///
286    /// # Example
287    ///
288    /// ```no_run
289    /// use inkwell::context::Context;
290    ///
291    /// let context = Context::create();
292    /// let i8_type = context.i8_type();
293    /// let i8_type_size = i8_type.size_of();
294    /// ```
295    pub fn size_of(self) -> IntValue<'ctx> {
296        self.int_type.size_of().unwrap()
297    }
298
299    /// Creates a `PointerType` with this `IntType` for its element type.
300    ///
301    /// # Example
302    ///
303    /// ```no_run
304    /// use inkwell::context::Context;
305    /// use inkwell::AddressSpace;
306    ///
307    /// let context = Context::create();
308    /// let i8_type = context.i8_type();
309    /// let i8_ptr_type = i8_type.ptr_type(AddressSpace::default());
310    ///
311    /// #[cfg(feature = "typed-pointers")]
312    /// assert_eq!(i8_ptr_type.get_element_type().into_int_type(), i8_type);
313    /// ```
314    #[cfg_attr(
315        any(
316            all(feature = "llvm15-0", not(feature = "typed-pointers")),
317            all(feature = "llvm16-0", not(feature = "typed-pointers")),
318            feature = "llvm17-0",
319            feature = "llvm18-1",
320            feature = "llvm19-1",
321            feature = "llvm20-1",
322            feature = "llvm21-1",
323        ),
324        deprecated(
325            note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
326        )
327    )]
328    pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {
329        self.int_type.ptr_type(address_space)
330    }
331
332    /// Gets the bit width of an `IntType`.
333    ///
334    /// # Example
335    /// ```no_run
336    /// use inkwell::context::Context;
337    ///
338    /// let context = Context::create();
339    /// let bool_type = context.bool_type();
340    ///
341    /// assert_eq!(bool_type.get_bit_width(), 1);
342    /// ```
343    pub fn get_bit_width(self) -> u32 {
344        unsafe { LLVMGetIntTypeWidth(self.as_type_ref()) }
345    }
346
347    /// Print the definition of an `IntType` to `LLVMString`.
348    pub fn print_to_string(self) -> LLVMString {
349        self.int_type.print_to_string()
350    }
351
352    /// Creates an undefined instance of an `IntType`.
353    ///
354    /// # Example
355    /// ```no_run
356    /// use inkwell::context::Context;
357    /// use inkwell::AddressSpace;
358    ///
359    /// let context = Context::create();
360    /// let i8_type = context.i8_type();
361    /// let i8_undef = i8_type.get_undef();
362    ///
363    /// assert!(i8_undef.is_undef());
364    /// ```
365    pub fn get_undef(self) -> IntValue<'ctx> {
366        unsafe { IntValue::new(self.int_type.get_undef()) }
367    }
368
369    /// Creates a poison instance of an `IntType`.
370    ///
371    /// # Example
372    /// ```no_run
373    /// use inkwell::context::Context;
374    /// use inkwell::AddressSpace;
375    /// use inkwell::values::AnyValue;
376    ///
377    /// let context = Context::create();
378    /// let i8_type = context.i8_type();
379    /// let i8_poison = i8_type.get_poison();
380    ///
381    /// assert!(i8_poison.is_poison());
382    /// ```
383    #[llvm_versions(12..)]
384    pub fn get_poison(self) -> IntValue<'ctx> {
385        unsafe { IntValue::new(self.int_type.get_poison()) }
386    }
387
388    /// Creates a `GenericValue` for use with `ExecutionEngine`s.
389    pub fn create_generic_value(self, value: u64, is_signed: bool) -> GenericValue<'ctx> {
390        unsafe { GenericValue::new(LLVMCreateGenericValueOfInt(self.as_type_ref(), value, is_signed as i32)) }
391    }
392
393    /// Creates a constant `ArrayValue`.
394    ///
395    /// # Example
396    /// ```no_run
397    /// use inkwell::context::Context;
398    ///
399    /// let context = Context::create();
400    /// let i8_type = context.i8_type();
401    /// let i8_val = i8_type.const_int(0, false);
402    /// let i8_val2 = i8_type.const_int(2, false);
403    /// let i8_array = i8_type.const_array(&[i8_val, i8_val2]);
404    ///
405    /// assert!(i8_array.is_const());
406    /// ```
407    pub fn const_array(self, values: &[IntValue<'ctx>]) -> ArrayValue<'ctx> {
408        unsafe { ArrayValue::new_const_array(&self, values) }
409    }
410}
411
412unsafe impl AsTypeRef for IntType<'_> {
413    fn as_type_ref(&self) -> LLVMTypeRef {
414        self.int_type.ty
415    }
416}
417
418impl Display for IntType<'_> {
419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420        write!(f, "{}", self.print_to_string())
421    }
422}