Skip to main content

inkwell/values/
int_value.rs

1#[llvm_versions(..=17)]
2use llvm_sys::core::{
3    LLVMConstAShr, LLVMConstAnd, LLVMConstIntCast, LLVMConstLShr, LLVMConstOr, LLVMConstSExt, LLVMConstSExtOrBitCast,
4    LLVMConstSIToFP, LLVMConstUIToFP, LLVMConstZExt, LLVMConstZExtOrBitCast,
5};
6use llvm_sys::core::{
7    LLVMConstAdd, LLVMConstBitCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr,
8    LLVMConstNSWAdd, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot,
9    LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstXor, LLVMIsAConstantInt,
10};
11#[llvm_versions(..=16)]
12use llvm_sys::core::{LLVMConstNUWNeg, LLVMConstSelect};
13
14#[llvm_versions(17..)]
15use llvm_sys::core::LLVMSetNUW;
16
17#[llvm_versions(..=18)]
18use llvm_sys::core::{LLVMConstICmp, LLVMConstShl};
19
20#[llvm_versions(..21)]
21use llvm_sys::core::{LLVMConstMul, LLVMConstNSWMul, LLVMConstNUWMul};
22
23use llvm_sys::prelude::LLVMValueRef;
24
25use std::convert::TryFrom;
26use std::ffi::CStr;
27use std::fmt::{self, Display};
28
29#[llvm_versions(..=17)]
30use crate::types::FloatType;
31use crate::types::{AsTypeRef, IntType, PointerType};
32use crate::values::traits::AsValueRef;
33#[llvm_versions(..=17)]
34use crate::values::FloatValue;
35#[llvm_versions(..=16)]
36use crate::values::{BasicValue, BasicValueEnum};
37use crate::values::{InstructionValue, PointerValue, Value};
38
39#[llvm_versions(..=18)]
40use crate::IntPredicate;
41
42use super::AnyValue;
43
44#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
45pub struct IntValue<'ctx> {
46    int_value: Value<'ctx>,
47}
48
49impl<'ctx> IntValue<'ctx> {
50    /// Get a value from an [LLVMValueRef].
51    ///
52    /// # Safety
53    ///
54    /// The ref must be valid and of type int.
55    pub unsafe fn new(value: LLVMValueRef) -> Self {
56        assert!(!value.is_null());
57
58        IntValue {
59            int_value: Value::new(value),
60        }
61    }
62
63    /// Gets the name of an `IntValue`. If the value is a constant, this will
64    /// return an empty string.
65    pub fn get_name(&self) -> &CStr {
66        self.int_value.get_name()
67    }
68
69    /// Set name of the `IntValue`.
70    pub fn set_name(&self, name: &str) {
71        self.int_value.set_name(name)
72    }
73
74    pub fn get_type(self) -> IntType<'ctx> {
75        unsafe { IntType::new(self.int_value.get_type()) }
76    }
77
78    pub fn is_null(self) -> bool {
79        self.int_value.is_null()
80    }
81
82    pub fn is_undef(self) -> bool {
83        self.int_value.is_undef()
84    }
85
86    pub fn print_to_stderr(self) {
87        self.int_value.print_to_stderr()
88    }
89
90    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
91        self.int_value.as_instruction()
92    }
93
94    pub fn const_not(self) -> Self {
95        unsafe { IntValue::new(LLVMConstNot(self.as_value_ref())) }
96    }
97
98    // REVIEW: What happens when not using a const value? This and other fns
99    pub fn const_neg(self) -> Self {
100        unsafe { IntValue::new(LLVMConstNeg(self.as_value_ref())) }
101    }
102
103    pub fn const_nsw_neg(self) -> Self {
104        unsafe { IntValue::new(LLVMConstNSWNeg(self.as_value_ref())) }
105    }
106
107    #[llvm_versions(..17)]
108    pub fn const_nuw_neg(self) -> Self {
109        unsafe { IntValue::new(LLVMConstNUWNeg(self.as_value_ref())) }
110    }
111
112    #[llvm_versions(17..)]
113    pub fn const_nuw_neg(self) -> Self {
114        let value = unsafe { LLVMConstNeg(self.as_value_ref()) };
115        unsafe {
116            LLVMSetNUW(value, true.into());
117        }
118        unsafe { IntValue::new(value) }
119    }
120
121    pub fn const_add(self, rhs: IntValue<'ctx>) -> Self {
122        unsafe { IntValue::new(LLVMConstAdd(self.as_value_ref(), rhs.as_value_ref())) }
123    }
124
125    pub fn const_nsw_add(self, rhs: IntValue<'ctx>) -> Self {
126        unsafe { IntValue::new(LLVMConstNSWAdd(self.as_value_ref(), rhs.as_value_ref())) }
127    }
128
129    pub fn const_nuw_add(self, rhs: IntValue<'ctx>) -> Self {
130        unsafe { IntValue::new(LLVMConstNUWAdd(self.as_value_ref(), rhs.as_value_ref())) }
131    }
132
133    pub fn const_sub(self, rhs: IntValue<'ctx>) -> Self {
134        unsafe { IntValue::new(LLVMConstSub(self.as_value_ref(), rhs.as_value_ref())) }
135    }
136
137    pub fn const_nsw_sub(self, rhs: IntValue<'ctx>) -> Self {
138        unsafe { IntValue::new(LLVMConstNSWSub(self.as_value_ref(), rhs.as_value_ref())) }
139    }
140
141    pub fn const_nuw_sub(self, rhs: IntValue<'ctx>) -> Self {
142        unsafe { IntValue::new(LLVMConstNUWSub(self.as_value_ref(), rhs.as_value_ref())) }
143    }
144
145    #[llvm_versions(..21)]
146    pub fn const_mul(self, rhs: IntValue<'ctx>) -> Self {
147        unsafe { IntValue::new(LLVMConstMul(self.as_value_ref(), rhs.as_value_ref())) }
148    }
149
150    #[llvm_versions(..21)]
151    pub fn const_nsw_mul(self, rhs: IntValue<'ctx>) -> Self {
152        unsafe { IntValue::new(LLVMConstNSWMul(self.as_value_ref(), rhs.as_value_ref())) }
153    }
154
155    #[llvm_versions(..21)]
156    pub fn const_nuw_mul(self, rhs: IntValue<'ctx>) -> Self {
157        unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) }
158    }
159
160    #[llvm_versions(..=14)]
161    pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self {
162        use llvm_sys::core::LLVMConstUDiv;
163
164        unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) }
165    }
166
167    #[llvm_versions(..=14)]
168    pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self {
169        use llvm_sys::core::LLVMConstSDiv;
170
171        unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) }
172    }
173
174    #[llvm_versions(..=14)]
175    pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self {
176        use llvm_sys::core::LLVMConstExactSDiv;
177
178        unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) }
179    }
180
181    #[llvm_versions(..=14)]
182    pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self {
183        use llvm_sys::core::LLVMConstExactUDiv;
184
185        unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) }
186    }
187
188    #[llvm_versions(..=14)]
189    pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self {
190        use llvm_sys::core::LLVMConstURem;
191
192        unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) }
193    }
194
195    #[llvm_versions(..=14)]
196    pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self {
197        use llvm_sys::core::LLVMConstSRem;
198
199        unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) }
200    }
201
202    #[llvm_versions(..=17)]
203    pub fn const_and(self, rhs: IntValue<'ctx>) -> Self {
204        unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) }
205    }
206
207    #[llvm_versions(..=17)]
208    pub fn const_or(self, rhs: IntValue<'ctx>) -> Self {
209        unsafe { IntValue::new(LLVMConstOr(self.as_value_ref(), rhs.as_value_ref())) }
210    }
211
212    pub fn const_xor(self, rhs: IntValue<'ctx>) -> Self {
213        unsafe { IntValue::new(LLVMConstXor(self.as_value_ref(), rhs.as_value_ref())) }
214    }
215
216    // TODO: Could infer is_signed from type (one day)?
217    #[llvm_versions(..=17)]
218    pub fn const_cast(self, int_type: IntType<'ctx>, is_signed: bool) -> Self {
219        unsafe {
220            IntValue::new(LLVMConstIntCast(
221                self.as_value_ref(),
222                int_type.as_type_ref(),
223                is_signed as i32,
224            ))
225        }
226    }
227
228    // TODO: Give shift methods more descriptive names
229    #[llvm_versions(..=18)]
230    pub fn const_shl(self, rhs: IntValue<'ctx>) -> Self {
231        unsafe { IntValue::new(LLVMConstShl(self.as_value_ref(), rhs.as_value_ref())) }
232    }
233
234    #[llvm_versions(..=17)]
235    pub fn const_rshr(self, rhs: IntValue<'ctx>) -> Self {
236        unsafe { IntValue::new(LLVMConstLShr(self.as_value_ref(), rhs.as_value_ref())) }
237    }
238
239    #[llvm_versions(..=17)]
240    pub fn const_ashr(self, rhs: IntValue<'ctx>) -> Self {
241        unsafe { IntValue::new(LLVMConstAShr(self.as_value_ref(), rhs.as_value_ref())) }
242    }
243
244    // SubType: const_to_float impl only for unsigned types
245    #[llvm_versions(..=17)]
246    pub fn const_unsigned_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
247        unsafe { FloatValue::new(LLVMConstUIToFP(self.as_value_ref(), float_type.as_type_ref())) }
248    }
249
250    // SubType: const_to_float impl only for signed types
251    #[llvm_versions(..=17)]
252    pub fn const_signed_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
253        unsafe { FloatValue::new(LLVMConstSIToFP(self.as_value_ref(), float_type.as_type_ref())) }
254    }
255
256    pub fn const_to_pointer(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> {
257        unsafe { PointerValue::new(LLVMConstIntToPtr(self.as_value_ref(), ptr_type.as_type_ref())) }
258    }
259
260    pub fn const_truncate(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
261        unsafe { IntValue::new(LLVMConstTrunc(self.as_value_ref(), int_type.as_type_ref())) }
262    }
263
264    // TODO: More descriptive name
265    #[llvm_versions(..=17)]
266    pub fn const_s_extend(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
267        unsafe { IntValue::new(LLVMConstSExt(self.as_value_ref(), int_type.as_type_ref())) }
268    }
269
270    // TODO: More descriptive name
271    #[llvm_versions(..=17)]
272    pub fn const_z_ext(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
273        unsafe { IntValue::new(LLVMConstZExt(self.as_value_ref(), int_type.as_type_ref())) }
274    }
275
276    pub fn const_truncate_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
277        unsafe { IntValue::new(LLVMConstTruncOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
278    }
279
280    // TODO: More descriptive name
281    #[llvm_versions(..=17)]
282    pub fn const_s_extend_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
283        unsafe { IntValue::new(LLVMConstSExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
284    }
285
286    // TODO: More descriptive name
287    #[llvm_versions(..=17)]
288    pub fn const_z_ext_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
289        unsafe { IntValue::new(LLVMConstZExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
290    }
291
292    pub fn const_bit_cast(self, int_type: IntType) -> IntValue<'ctx> {
293        unsafe { IntValue::new(LLVMConstBitCast(self.as_value_ref(), int_type.as_type_ref())) }
294    }
295
296    // SubType: rhs same as lhs; return IntValue<bool>
297    #[llvm_versions(..=18)]
298    pub fn const_int_compare(self, op: IntPredicate, rhs: IntValue<'ctx>) -> IntValue<'ctx> {
299        unsafe { IntValue::new(LLVMConstICmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) }
300    }
301
302    // SubTypes: self can only be IntValue<bool>
303    #[llvm_versions(..=16)]
304    pub fn const_select<BV: BasicValue<'ctx>>(self, then: BV, else_: BV) -> BasicValueEnum<'ctx> {
305        unsafe {
306            BasicValueEnum::new(LLVMConstSelect(
307                self.as_value_ref(),
308                then.as_value_ref(),
309                else_.as_value_ref(),
310            ))
311        }
312    }
313
314    /// Determines whether or not an `IntValue` is an `llvm::Constant`.
315    ///
316    /// Constants includes values that are not known at compile time, for
317    /// example the address of a function casted to an integer.
318    ///
319    /// # Example
320    ///
321    /// ```no_run
322    /// use inkwell::context::Context;
323    ///
324    /// let context = Context::create();
325    /// let i64_type = context.i64_type();
326    /// let i64_val = i64_type.const_int(12, false);
327    ///
328    /// assert!(i64_val.is_const());
329    /// ```
330    pub fn is_const(self) -> bool {
331        self.int_value.is_const()
332    }
333
334    /// Determines whether or not an `IntValue` is an `llvm::ConstantInt`.
335    ///
336    /// ConstantInt only includes values that are known at compile time.
337    ///
338    /// # Example
339    ///
340    /// ```no_run
341    /// use inkwell::context::Context;
342    ///
343    /// let context = Context::create();
344    /// let i64_type = context.i64_type();
345    /// let i64_val = i64_type.const_int(12, false);
346    ///
347    /// assert!(i64_val.is_constant_int());
348    /// ```
349    pub fn is_constant_int(self) -> bool {
350        !unsafe { LLVMIsAConstantInt(self.as_value_ref()) }.is_null()
351    }
352
353    /// Obtains a constant `IntValue`'s zero extended value.
354    ///
355    /// # Example
356    ///
357    /// ```no_run
358    /// use inkwell::context::Context;
359    ///
360    /// let context = Context::create();
361    /// let i8_type = context.i8_type();
362    /// let i8_all_ones = i8_type.const_all_ones();
363    ///
364    /// assert_eq!(i8_all_ones.get_zero_extended_constant(), Some(255));
365    /// ```
366    pub fn get_zero_extended_constant(self) -> Option<u64> {
367        // Garbage values are produced on non constant values
368        if !self.is_constant_int() {
369            return None;
370        }
371        if self.get_type().get_bit_width() > 64 {
372            return None;
373        }
374
375        unsafe { Some(LLVMConstIntGetZExtValue(self.as_value_ref())) }
376    }
377
378    /// Obtains a constant `IntValue`'s sign extended value.
379    ///
380    /// # Example
381    ///
382    /// ```no_run
383    /// use inkwell::context::Context;
384    ///
385    /// let context = Context::create();
386    /// let i8_type = context.i8_type();
387    /// let i8_all_ones = i8_type.const_all_ones();
388    ///
389    /// assert_eq!(i8_all_ones.get_sign_extended_constant(), Some(-1));
390    /// ```
391    pub fn get_sign_extended_constant(self) -> Option<i64> {
392        // Garbage values are produced on non constant values
393        if !self.is_constant_int() {
394            return None;
395        }
396        if self.get_type().get_bit_width() > 64 {
397            return None;
398        }
399
400        unsafe { Some(LLVMConstIntGetSExtValue(self.as_value_ref())) }
401    }
402
403    pub fn replace_all_uses_with(self, other: IntValue<'ctx>) {
404        self.int_value.replace_all_uses_with(other.as_value_ref())
405    }
406}
407
408unsafe impl AsValueRef for IntValue<'_> {
409    fn as_value_ref(&self) -> LLVMValueRef {
410        self.int_value.value
411    }
412}
413
414impl Display for IntValue<'_> {
415    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416        write!(f, "{}", self.print_to_string())
417    }
418}
419
420impl<'ctx> TryFrom<InstructionValue<'ctx>> for IntValue<'ctx> {
421    type Error = ();
422
423    fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
424        if value.get_type().is_int_type() {
425            unsafe { Ok(IntValue::new(value.as_value_ref())) }
426        } else {
427            Err(())
428        }
429    }
430}