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}