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