llvm_plugin_inkwell/values/
global_value.rs

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