Skip to main content

inkwell/values/
global_value.rs

1use llvm_sys::core::LLVMGlobalSetMetadata;
2
3use llvm_sys::core::{
4    LLVMDeleteGlobal, LLVMGetAlignment, LLVMGetDLLStorageClass, LLVMGetInitializer, LLVMGetLinkage, LLVMGetNextGlobal,
5    LLVMGetPreviousGlobal, LLVMGetThreadLocalMode, LLVMGetVisibility, LLVMIsDeclaration, LLVMIsExternallyInitialized,
6    LLVMIsGlobalConstant, LLVMIsThreadLocal, LLVMSetAlignment, LLVMSetDLLStorageClass, LLVMSetExternallyInitialized,
7    LLVMSetGlobalConstant, LLVMSetInitializer, LLVMSetLinkage, LLVMSetThreadLocal, LLVMSetThreadLocalMode,
8    LLVMSetVisibility,
9};
10
11use llvm_sys::core::{LLVMGetUnnamedAddress, LLVMSetUnnamedAddress};
12use llvm_sys::prelude::LLVMValueRef;
13use llvm_sys::LLVMThreadLocalMode;
14
15use llvm_sys::LLVMUnnamedAddr;
16
17use std::ffi::CStr;
18use std::fmt::{self, Display};
19
20use crate::comdat::Comdat;
21use crate::module::Linkage;
22use crate::types::AnyTypeEnum;
23use crate::values::traits::AsValueRef;
24
25use crate::values::MetadataValue;
26use crate::values::{BasicValue, BasicValueEnum, PointerValue, Value};
27use crate::{DLLStorageClass, GlobalVisibility, ThreadLocalMode};
28
29use super::AnyValue;
30
31// REVIEW: GlobalValues are always PointerValues. With SubTypes, we should
32// compress this into a PointerValue<Global> type
33#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
34pub struct GlobalValue<'ctx> {
35    global_value: Value<'ctx>,
36}
37
38impl<'ctx> GlobalValue<'ctx> {
39    /// Get a value from an [LLVMValueRef].
40    ///
41    /// # Safety
42    ///
43    /// The ref must be valid and of type global.
44    pub unsafe fn new(value: LLVMValueRef) -> Self {
45        assert!(!value.is_null());
46
47        GlobalValue {
48            global_value: Value::new(value),
49        }
50    }
51
52    /// Get name of the `GlobalValue`.
53    pub fn get_name(&self) -> &CStr {
54        self.global_value.get_name()
55    }
56
57    /// Set name of the `GlobalValue`.
58    pub fn set_name(&self, name: &str) {
59        self.global_value.set_name(name)
60    }
61
62    pub fn get_previous_global(self) -> Option<GlobalValue<'ctx>> {
63        let value = unsafe { LLVMGetPreviousGlobal(self.as_value_ref()) };
64
65        if value.is_null() {
66            return None;
67        }
68
69        unsafe { Some(GlobalValue::new(value)) }
70    }
71
72    pub fn get_next_global(self) -> Option<GlobalValue<'ctx>> {
73        let value = unsafe { LLVMGetNextGlobal(self.as_value_ref()) };
74
75        if value.is_null() {
76            return None;
77        }
78
79        unsafe { Some(GlobalValue::new(value)) }
80    }
81
82    pub fn get_dll_storage_class(self) -> DLLStorageClass {
83        let dll_storage_class = unsafe { LLVMGetDLLStorageClass(self.as_value_ref()) };
84
85        DLLStorageClass::new(dll_storage_class)
86    }
87
88    pub fn set_dll_storage_class(self, dll_storage_class: DLLStorageClass) {
89        unsafe { LLVMSetDLLStorageClass(self.as_value_ref(), dll_storage_class.into()) }
90    }
91
92    pub fn get_initializer(self) -> Option<BasicValueEnum<'ctx>> {
93        let value = unsafe { LLVMGetInitializer(self.as_value_ref()) };
94
95        if value.is_null() {
96            return None;
97        }
98
99        unsafe { Some(BasicValueEnum::new(value)) }
100    }
101
102    // SubType: This input type should be tied to the BasicType
103    pub fn set_initializer(self, value: &dyn BasicValue<'ctx>) {
104        unsafe { LLVMSetInitializer(self.as_value_ref(), value.as_value_ref()) }
105    }
106
107    pub fn is_thread_local(self) -> bool {
108        unsafe { LLVMIsThreadLocal(self.as_value_ref()) == 1 }
109    }
110
111    // TODOC: Setting this to true is the same as setting GeneralDynamicTLSModel
112    pub fn set_thread_local(self, is_thread_local: bool) {
113        unsafe { LLVMSetThreadLocal(self.as_value_ref(), is_thread_local as i32) }
114    }
115
116    pub fn get_thread_local_mode(self) -> Option<ThreadLocalMode> {
117        let thread_local_mode = unsafe { LLVMGetThreadLocalMode(self.as_value_ref()) };
118
119        ThreadLocalMode::new(thread_local_mode)
120    }
121
122    // REVIEW: Does this have any bad behavior if it isn't thread local or just a noop?
123    // or should it call self.set_thread_local(true)?
124    pub fn set_thread_local_mode(self, thread_local_mode: Option<ThreadLocalMode>) {
125        let thread_local_mode = match thread_local_mode {
126            Some(mode) => mode.as_llvm_mode(),
127            None => LLVMThreadLocalMode::LLVMNotThreadLocal,
128        };
129
130        unsafe { LLVMSetThreadLocalMode(self.as_value_ref(), thread_local_mode) }
131    }
132
133    // SubType: This should be moved into the type. GlobalValue<Initialized/Uninitialized>
134    /// Determines whether or not a `GlobalValue` is a declaration or a definition.
135    ///
136    /// # Example
137    ///
138    /// ```no_run
139    /// use inkwell::context::Context;
140    ///
141    /// let context = Context::create();
142    /// let builder = context.create_builder();
143    /// let module = context.create_module("my_mod");
144    /// let void_type = context.void_type();
145    /// let fn_type = void_type.fn_type(&[], false);
146    /// let fn_value = module.add_function("my_func", fn_type, None);
147    ///
148    /// assert!(fn_value.as_global_value().is_declaration());
149    ///
150    /// context.append_basic_block(fn_value, "entry");
151    ///
152    /// assert!(!fn_value.as_global_value().is_declaration());
153    /// ```
154    pub fn is_declaration(self) -> bool {
155        unsafe { LLVMIsDeclaration(self.as_value_ref()) == 1 }
156    }
157
158    pub fn has_unnamed_addr(self) -> bool {
159        unsafe { LLVMGetUnnamedAddress(self.as_value_ref()) == LLVMUnnamedAddr::LLVMGlobalUnnamedAddr }
160    }
161
162    pub fn set_unnamed_addr(self, has_unnamed_addr: bool) {
163        unsafe {
164            if has_unnamed_addr {
165                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::Global.into())
166            } else {
167                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::None.into())
168            }
169        }
170    }
171
172    pub fn is_constant(self) -> bool {
173        unsafe { LLVMIsGlobalConstant(self.as_value_ref()) == 1 }
174    }
175
176    pub fn set_constant(self, is_constant: bool) {
177        unsafe { LLVMSetGlobalConstant(self.as_value_ref(), is_constant as i32) }
178    }
179
180    pub fn is_externally_initialized(self) -> bool {
181        unsafe { LLVMIsExternallyInitialized(self.as_value_ref()) == 1 }
182    }
183
184    pub fn set_externally_initialized(self, externally_initialized: bool) {
185        unsafe { LLVMSetExternallyInitialized(self.as_value_ref(), externally_initialized as i32) }
186    }
187
188    pub fn set_visibility(self, visibility: GlobalVisibility) {
189        unsafe { LLVMSetVisibility(self.as_value_ref(), visibility.into()) }
190    }
191
192    pub fn get_visibility(self) -> GlobalVisibility {
193        let visibility = unsafe { LLVMGetVisibility(self.as_value_ref()) };
194
195        GlobalVisibility::new(visibility)
196    }
197
198    /// Get section, this global value belongs to
199    pub fn get_section(&self) -> Option<&CStr> {
200        self.global_value.get_section()
201    }
202
203    /// Set section, this global value belongs to
204    pub fn set_section(self, section: Option<&str>) {
205        self.global_value.set_section(section)
206    }
207
208    pub unsafe fn delete(self) {
209        LLVMDeleteGlobal(self.as_value_ref())
210    }
211
212    pub fn as_pointer_value(self) -> PointerValue<'ctx> {
213        unsafe { PointerValue::new(self.as_value_ref()) }
214    }
215
216    pub fn get_alignment(self) -> u32 {
217        unsafe { LLVMGetAlignment(self.as_value_ref()) }
218    }
219
220    pub fn set_alignment(self, alignment: u32) {
221        unsafe { LLVMSetAlignment(self.as_value_ref(), alignment) }
222    }
223
224    /// Sets a metadata of the given type on the GlobalValue
225    pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) {
226        unsafe { LLVMGlobalSetMetadata(self.as_value_ref(), kind_id, metadata.as_metadata_ref()) }
227    }
228
229    /// Gets a `Comdat` assigned to this `GlobalValue`, if any.
230    pub fn get_comdat(self) -> Option<Comdat> {
231        use llvm_sys::comdat::LLVMGetComdat;
232
233        let comdat_ptr = unsafe { LLVMGetComdat(self.as_value_ref()) };
234
235        if comdat_ptr.is_null() {
236            return None;
237        }
238
239        unsafe { Some(Comdat::new(comdat_ptr)) }
240    }
241
242    /// Assigns a `Comdat` to this `GlobalValue`.
243    pub fn set_comdat(self, comdat: Comdat) {
244        use llvm_sys::comdat::LLVMSetComdat;
245
246        unsafe { LLVMSetComdat(self.as_value_ref(), comdat.0) }
247    }
248
249    pub fn get_unnamed_address(self) -> UnnamedAddress {
250        use llvm_sys::core::LLVMGetUnnamedAddress;
251
252        let unnamed_address = unsafe { LLVMGetUnnamedAddress(self.as_value_ref()) };
253
254        UnnamedAddress::new(unnamed_address)
255    }
256
257    pub fn set_unnamed_address(self, address: UnnamedAddress) {
258        use llvm_sys::core::LLVMSetUnnamedAddress;
259
260        unsafe { LLVMSetUnnamedAddress(self.as_value_ref(), address.into()) }
261    }
262
263    pub fn get_linkage(self) -> Linkage {
264        unsafe { LLVMGetLinkage(self.as_value_ref()).into() }
265    }
266
267    pub fn set_linkage(self, linkage: Linkage) {
268        unsafe { LLVMSetLinkage(self.as_value_ref(), linkage.into()) }
269    }
270
271    pub fn get_value_type(self) -> AnyTypeEnum<'ctx> {
272        unsafe { AnyTypeEnum::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
273    }
274}
275
276unsafe impl AsValueRef for GlobalValue<'_> {
277    fn as_value_ref(&self) -> LLVMValueRef {
278        self.global_value.value
279    }
280}
281
282impl Display for GlobalValue<'_> {
283    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284        write!(f, "{}", self.print_to_string())
285    }
286}
287
288/// This enum determines the significance of a `GlobalValue`'s address.
289
290#[llvm_enum(LLVMUnnamedAddr)]
291#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
292pub enum UnnamedAddress {
293    /// Address of the `GlobalValue` is significant.
294    #[llvm_variant(LLVMNoUnnamedAddr)]
295    None,
296
297    /// Address of the `GlobalValue` is locally insignificant.
298    #[llvm_variant(LLVMLocalUnnamedAddr)]
299    Local,
300
301    /// Address of the `GlobalValue` is globally insignificant.
302    #[llvm_variant(LLVMGlobalUnnamedAddr)]
303    Global,
304}