inkwell/values/
ptr_value.rs

1#[cfg(all(feature = "typed-pointers", not(feature = "llvm16-0")))]
2#[cfg_attr(feature = "llvm15-0", allow(deprecated))]
3use llvm_sys::core::{LLVMConstGEP, LLVMConstInBoundsGEP};
4#[cfg(any(not(feature = "typed-pointers"), feature = "llvm16-0"))]
5use llvm_sys::core::{LLVMConstGEP2, LLVMConstInBoundsGEP2};
6
7use llvm_sys::core::{LLVMConstAddrSpaceCast, LLVMConstPointerCast, LLVMConstPtrToInt};
8use llvm_sys::prelude::LLVMValueRef;
9
10use std::convert::TryFrom;
11use std::ffi::CStr;
12use std::fmt::{self, Display};
13
14#[cfg(not(feature = "typed-pointers"))]
15use crate::types::BasicType;
16use crate::types::{AsTypeRef, IntType, PointerType};
17use crate::values::{AsValueRef, InstructionValue, IntValue, Value};
18
19use super::AnyValue;
20
21#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
22pub struct PointerValue<'ctx> {
23    ptr_value: Value<'ctx>,
24}
25
26impl<'ctx> PointerValue<'ctx> {
27    /// Get a value from an [LLVMValueRef].
28    ///
29    /// # Safety
30    ///
31    /// The ref must be valid and of type pointer.
32    pub unsafe fn new(value: LLVMValueRef) -> Self {
33        assert!(!value.is_null());
34
35        PointerValue {
36            ptr_value: Value::new(value),
37        }
38    }
39
40    /// Get name of the `PointerValue`. If the value is a constant, this
41    /// will return an empty string.
42    pub fn get_name(&self) -> &CStr {
43        self.ptr_value.get_name()
44    }
45
46    /// Set name of the `PointerValue`.
47    pub fn set_name(&self, name: &str) {
48        self.ptr_value.set_name(name)
49    }
50
51    pub fn get_type(self) -> PointerType<'ctx> {
52        unsafe { PointerType::new(self.ptr_value.get_type()) }
53    }
54
55    pub fn is_null(self) -> bool {
56        self.ptr_value.is_null()
57    }
58
59    pub fn is_undef(self) -> bool {
60        self.ptr_value.is_undef()
61    }
62
63    /// Determines whether or not a `PointerValue` is a constant.
64    ///
65    /// # Example
66    ///
67    /// ```no_run
68    /// use inkwell::AddressSpace;
69    /// use inkwell::context::Context;
70    ///
71    /// let context = Context::create();
72    /// let void_type = context.void_type();
73    /// ```
74    pub fn is_const(self) -> bool {
75        self.ptr_value.is_const()
76    }
77
78    pub fn print_to_stderr(self) {
79        self.ptr_value.print_to_stderr()
80    }
81
82    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
83        self.ptr_value.as_instruction()
84    }
85
86    // REVIEW: Should this be on array value too?
87    /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
88    #[cfg(feature = "typed-pointers")]
89    pub unsafe fn const_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
90        let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
91
92        #[cfg(not(feature = "llvm16-0"))]
93        #[cfg_attr(feature = "llvm15-0", allow(deprecated))]
94        let value = {
95            LLVMConstGEP(
96                self.as_value_ref(),
97                index_values.as_mut_ptr(),
98                index_values.len() as u32,
99            )
100        };
101        #[cfg(feature = "llvm16-0")]
102        let value = {
103            LLVMConstGEP2(
104                self.get_type().get_element_type().as_type_ref(),
105                self.as_value_ref(),
106                index_values.as_mut_ptr(),
107                index_values.len() as u32,
108            )
109        };
110
111        PointerValue::new(value)
112    }
113
114    // REVIEW: Should this be on array value too?
115    /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
116    #[cfg(not(feature = "typed-pointers"))]
117    pub unsafe fn const_gep<T: BasicType<'ctx>>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
118        let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
119
120        let value = {
121            LLVMConstGEP2(
122                ty.as_type_ref(),
123                self.as_value_ref(),
124                index_values.as_mut_ptr(),
125                index_values.len() as u32,
126            )
127        };
128
129        PointerValue::new(value)
130    }
131
132    /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
133    #[cfg(feature = "typed-pointers")]
134    pub unsafe fn const_in_bounds_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
135        let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
136
137        #[cfg(not(feature = "llvm16-0"))]
138        #[cfg_attr(feature = "llvm15-0", allow(deprecated))]
139        let value = {
140            LLVMConstInBoundsGEP(
141                self.as_value_ref(),
142                index_values.as_mut_ptr(),
143                index_values.len() as u32,
144            )
145        };
146        #[cfg(feature = "llvm16-0")]
147        let value = {
148            LLVMConstInBoundsGEP2(
149                self.get_type().get_element_type().as_type_ref(),
150                self.as_value_ref(),
151                index_values.as_mut_ptr(),
152                index_values.len() as u32,
153            )
154        };
155
156        PointerValue::new(value)
157    }
158
159    /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
160    #[cfg(not(feature = "typed-pointers"))]
161    pub unsafe fn const_in_bounds_gep<T: BasicType<'ctx>>(
162        self,
163        ty: T,
164        ordered_indexes: &[IntValue<'ctx>],
165    ) -> PointerValue<'ctx> {
166        let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
167
168        let value = {
169            LLVMConstInBoundsGEP2(
170                ty.as_type_ref(),
171                self.as_value_ref(),
172                index_values.as_mut_ptr(),
173                index_values.len() as u32,
174            )
175        };
176
177        PointerValue::new(value)
178    }
179}
180
181impl<'ctx> PointerValue<'ctx> {
182    pub fn const_to_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
183        unsafe { IntValue::new(LLVMConstPtrToInt(self.as_value_ref(), int_type.as_type_ref())) }
184    }
185
186    pub fn const_cast(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> {
187        unsafe { PointerValue::new(LLVMConstPointerCast(self.as_value_ref(), ptr_type.as_type_ref())) }
188    }
189
190    pub fn const_address_space_cast(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> {
191        unsafe { PointerValue::new(LLVMConstAddrSpaceCast(self.as_value_ref(), ptr_type.as_type_ref())) }
192    }
193
194    pub fn replace_all_uses_with(self, other: PointerValue<'ctx>) {
195        self.ptr_value.replace_all_uses_with(other.as_value_ref())
196    }
197}
198
199unsafe impl AsValueRef for PointerValue<'_> {
200    fn as_value_ref(&self) -> LLVMValueRef {
201        self.ptr_value.value
202    }
203}
204
205impl Display for PointerValue<'_> {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        write!(f, "{}", self.print_to_string())
208    }
209}
210
211impl<'ctx> TryFrom<InstructionValue<'ctx>> for PointerValue<'ctx> {
212    type Error = ();
213
214    fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
215        if value.get_type().is_pointer_type() {
216            unsafe { Ok(PointerValue::new(value.as_value_ref())) }
217        } else {
218            Err(())
219        }
220    }
221}