inkwell/values/
mod.rs

1//! A value is an instance of a type.
2
3#[deny(missing_docs)]
4mod array_value;
5#[deny(missing_docs)]
6mod basic_value_use;
7#[deny(missing_docs)]
8mod call_site_value;
9mod enums;
10mod float_value;
11mod fn_value;
12mod generic_value;
13mod global_value;
14mod instruction_value;
15mod int_value;
16mod metadata_value;
17mod phi_value;
18mod ptr_value;
19mod scalable_vec_value;
20mod struct_value;
21mod traits;
22mod vec_value;
23
24#[cfg(feature = "llvm18-0")]
25pub(crate) mod operand_bundle;
26
27#[cfg(not(any(
28    feature = "llvm15-0",
29    feature = "llvm16-0",
30    feature = "llvm17-0",
31    feature = "llvm18-0"
32)))]
33mod callable_value;
34
35#[cfg(not(any(
36    feature = "llvm15-0",
37    feature = "llvm16-0",
38    feature = "llvm17-0",
39    feature = "llvm18-0"
40)))]
41pub use crate::values::callable_value::CallableValue;
42
43#[llvm_versions(18..)]
44pub use crate::values::operand_bundle::OperandBundle;
45
46use crate::support::{to_c_str, LLVMString};
47pub use crate::values::array_value::ArrayValue;
48pub use crate::values::basic_value_use::BasicValueUse;
49pub use crate::values::call_site_value::CallSiteValue;
50pub use crate::values::enums::{AggregateValueEnum, AnyValueEnum, BasicMetadataValueEnum, BasicValueEnum};
51pub use crate::values::float_value::FloatValue;
52pub use crate::values::fn_value::FunctionValue;
53pub use crate::values::generic_value::GenericValue;
54pub use crate::values::global_value::GlobalValue;
55#[llvm_versions(7..)]
56pub use crate::values::global_value::UnnamedAddress;
57pub use crate::values::instruction_value::{InstructionOpcode, InstructionValue, OperandIter, OperandUseIter};
58pub use crate::values::int_value::IntValue;
59pub use crate::values::metadata_value::{MetadataValue, FIRST_CUSTOM_METADATA_KIND_ID};
60pub use crate::values::phi_value::IncomingIter;
61pub use crate::values::phi_value::PhiValue;
62pub use crate::values::ptr_value::PointerValue;
63pub use crate::values::scalable_vec_value::ScalableVectorValue;
64pub use crate::values::struct_value::FieldValueIter;
65pub use crate::values::struct_value::StructValue;
66pub use crate::values::traits::AsValueRef;
67pub use crate::values::traits::{
68    AggregateValue, AnyValue, BasicValue, FloatMathValue, IntMathValue, PointerMathValue, VectorBaseValue,
69};
70pub use crate::values::vec_value::VectorValue;
71
72#[llvm_versions(18..)]
73pub use llvm_sys::LLVMTailCallKind;
74
75use llvm_sys::core::{
76    LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull, LLVMIsUndef,
77    LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection, LLVMTypeOf,
78};
79use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
80
81use std::ffi::CStr;
82use std::fmt;
83use std::marker::PhantomData;
84
85#[derive(PartialEq, Eq, Clone, Copy, Hash)]
86struct Value<'ctx> {
87    value: LLVMValueRef,
88    _marker: PhantomData<&'ctx ()>,
89}
90
91impl<'ctx> Value<'ctx> {
92    pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
93        debug_assert!(
94            !value.is_null(),
95            "This should never happen since containing struct should check null ptrs"
96        );
97
98        Value {
99            value,
100            _marker: PhantomData,
101        }
102    }
103
104    fn is_instruction(self) -> bool {
105        unsafe { !LLVMIsAInstruction(self.value).is_null() }
106    }
107
108    fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
109        if !self.is_instruction() {
110            return None;
111        }
112
113        unsafe { Some(InstructionValue::new(self.value)) }
114    }
115
116    fn is_null(self) -> bool {
117        unsafe { LLVMIsNull(self.value) == 1 }
118    }
119
120    fn is_const(self) -> bool {
121        unsafe { LLVMIsConstant(self.value) == 1 }
122    }
123
124    // TODOC: According to https://stackoverflow.com/questions/21593752/llvm-how-to-pass-a-name-to-constantint
125    // you can't use set_name name on a constant(by can't, I mean it wont do anything), unless it's also a global.
126    // So, you can set names on variables (ie a function parameter)
127    // REVIEW: It'd be great if we could encode this into the type system somehow. For example,
128    // add a ParamValue wrapper type that always have it but conditional types (IntValue<Variable>)
129    // that also have it. This isn't a huge deal though, since it hasn't proven to be UB so far
130    fn set_name(self, name: &str) {
131        let c_string = to_c_str(name);
132
133        #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
134        {
135            use llvm_sys::core::LLVMSetValueName;
136
137            unsafe {
138                LLVMSetValueName(self.value, c_string.as_ptr());
139            }
140        }
141        #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
142        {
143            use llvm_sys::core::LLVMSetValueName2;
144
145            unsafe { LLVMSetValueName2(self.value, c_string.as_ptr(), c_string.to_bytes().len()) }
146        }
147    }
148
149    // get_name should *not* return a LLVMString, because it is not an owned value AFAICT
150    // TODO: Should make this take ownership of self. But what is the lifetime of the string? 'ctx?
151    fn get_name(&self) -> &CStr {
152        #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
153        let ptr = unsafe {
154            use llvm_sys::core::LLVMGetValueName;
155
156            LLVMGetValueName(self.value)
157        };
158        #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
159        let ptr = unsafe {
160            use llvm_sys::core::LLVMGetValueName2;
161            let mut len = 0;
162
163            LLVMGetValueName2(self.value, &mut len)
164        };
165
166        unsafe { CStr::from_ptr(ptr) }
167    }
168
169    fn is_undef(self) -> bool {
170        unsafe { LLVMIsUndef(self.value) == 1 }
171    }
172
173    fn get_type(self) -> LLVMTypeRef {
174        unsafe { LLVMTypeOf(self.value) }
175    }
176
177    fn print_to_string(self) -> LLVMString {
178        unsafe { LLVMString::new(LLVMPrintValueToString(self.value)) }
179    }
180
181    fn print_to_stderr(self) {
182        unsafe { LLVMDumpValue(self.value) }
183    }
184
185    // REVIEW: I think this is memory safe, though it may result in an IR error
186    // if used incorrectly, which is OK.
187    fn replace_all_uses_with(self, other: LLVMValueRef) {
188        // LLVM may infinite-loop when they aren't distinct, which is UB in C++.
189        if self.value != other {
190            unsafe { LLVMReplaceAllUsesWith(self.value, other) }
191        }
192    }
193
194    pub fn get_first_use(self) -> Option<BasicValueUse<'ctx>> {
195        let use_ = unsafe { LLVMGetFirstUse(self.value) };
196
197        if use_.is_null() {
198            return None;
199        }
200
201        unsafe { Some(BasicValueUse::new(use_)) }
202    }
203
204    /// Gets the section of the global value
205    pub fn get_section(&self) -> Option<&CStr> {
206        let ptr = unsafe { LLVMGetSection(self.value) };
207
208        if ptr.is_null() {
209            return None;
210        }
211
212        // On MacOS we need to remove ',' before section name
213        if cfg!(target_os = "macos") {
214            let name = unsafe { CStr::from_ptr(ptr) };
215            let name_string = name.to_string_lossy();
216            let mut chars = name_string.chars();
217            if Some(',') == chars.next() {
218                Some(unsafe { CStr::from_ptr(ptr.add(1)) })
219            } else {
220                Some(name)
221            }
222        } else {
223            Some(unsafe { CStr::from_ptr(ptr) })
224        }
225    }
226
227    /// Sets the section of the global value
228    fn set_section(self, section: Option<&str>) {
229        #[cfg(target_os = "macos")]
230        let mapped_section = section.map(|s| {
231            if s.contains(",") {
232                format!("{}", s)
233            } else {
234                format!(",{}", s)
235            }
236        });
237        #[cfg(target_os = "macos")]
238        let section = mapped_section.as_deref();
239
240        let c_string = section.map(to_c_str);
241
242        unsafe {
243            LLVMSetSection(
244                self.value,
245                // The as_ref call is important here so that we don't drop the cstr mid use
246                c_string.as_ref().map(|s| s.as_ptr()).unwrap_or(std::ptr::null()),
247            )
248        }
249    }
250}
251
252impl fmt::Debug for Value<'_> {
253    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254        let llvm_value = self.print_to_string();
255        let llvm_type = unsafe { CStr::from_ptr(LLVMPrintTypeToString(LLVMTypeOf(self.value))) };
256        let name = self.get_name();
257        let is_const = self.is_const();
258        let is_null = self.is_null();
259        let is_undef = self.is_undef();
260
261        f.debug_struct("Value")
262            .field("name", &name)
263            .field("address", &self.value)
264            .field("is_const", &is_const)
265            .field("is_null", &is_null)
266            .field("is_undef", &is_undef)
267            .field("llvm_value", &llvm_value)
268            .field("llvm_type", &llvm_type)
269            .finish()
270    }
271}