llvm_plugin_inkwell/values/
ptr_value.rs

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