inkwell/values/
int_value.rs

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