llvm_plugin_inkwell/values/
int_value.rs

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