Skip to main content

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