llvm_lib/core/values/constants/global_variables.rs
1use super::{TypeRef, ValueRef};
2use crate::core::module::ModuleRef;
3use crate::core::AddressSpace;
4use crate::{CInt, CString, GetRef};
5use llvm_sys::{core, LLVMThreadLocalMode};
6
7/// Represents the thread-local storage (TLS) model for a global variable in LLVM.
8///
9/// Thread-local storage allows each thread to have its own instance of a global variable. The different TLS models
10/// dictate how the runtime handles accessing the variable across threads and whether the variable is accessed
11/// dynamically or statically.
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum ThreadLocalMode {
14 /// The global variable is not thread-local.
15 NotThreadLocal,
16 /// General dynamic TLS model, suitable for global variables that are accessed across
17 /// multiple modules and can be dynamically allocated for each thread.
18 GeneralDynamicTLSModel,
19 /// Local dynamic TLS model, suitable for global variables that are dynamically allocated
20 /// but only accessed within the same module.
21 LocalDynamicTLSModel,
22 /// Initial execution TLS model, allowing for faster access to TLS variables when they are
23 /// known to be used early during program execution (such as in dynamic libraries).
24 InitialExecTLSModel,
25 /// Local execution TLS model, providing fast access to thread-local variables that are
26 /// only accessed within the current module, without requiring relocation.
27 LocalExecTLSModel,
28}
29
30impl From<LLVMThreadLocalMode> for ThreadLocalMode {
31 fn from(mode: LLVMThreadLocalMode) -> Self {
32 match mode {
33 LLVMThreadLocalMode::LLVMNotThreadLocal => Self::NotThreadLocal,
34 LLVMThreadLocalMode::LLVMGeneralDynamicTLSModel => Self::GeneralDynamicTLSModel,
35 LLVMThreadLocalMode::LLVMLocalDynamicTLSModel => Self::LocalDynamicTLSModel,
36 LLVMThreadLocalMode::LLVMInitialExecTLSModel => Self::InitialExecTLSModel,
37 LLVMThreadLocalMode::LLVMLocalExecTLSModel => Self::LocalExecTLSModel,
38 }
39 }
40}
41
42impl From<ThreadLocalMode> for LLVMThreadLocalMode {
43 fn from(mode: ThreadLocalMode) -> Self {
44 match mode {
45 ThreadLocalMode::NotThreadLocal => Self::LLVMNotThreadLocal,
46 ThreadLocalMode::GeneralDynamicTLSModel => Self::LLVMGeneralDynamicTLSModel,
47 ThreadLocalMode::LocalDynamicTLSModel => Self::LLVMLocalDynamicTLSModel,
48 ThreadLocalMode::InitialExecTLSModel => Self::LLVMInitialExecTLSModel,
49 ThreadLocalMode::LocalExecTLSModel => Self::LLVMLocalExecTLSModel,
50 }
51 }
52}
53
54/// Adds a new global variable of the specified type to the module.
55///
56/// This function wraps the `LLVMAddGlobal` function from the LLVM core library. It creates a new global variable
57/// in the current module, with the provided type and name. The global variable is initialized with a null value by default
58/// and can be further configured using other methods such as setting an initializer or modifying its linkage.
59///
60/// # Parameters
61///
62/// - `ty`: A reference to the `TypeRef` representing the type of the global variable.
63/// - `name`: A string slice (`&str`) representing the name of the global variable.
64///
65/// # Returns
66///
67/// Returns a `ValueRef` representing the newly added global variable.
68#[must_use]
69pub fn add_global(m: &ModuleRef, ty: &TypeRef, name: &str) -> ValueRef {
70 let c_name = CString::from(name);
71 unsafe {
72 ValueRef(core::LLVMAddGlobal(
73 m.get_ref(),
74 ty.get_ref(),
75 c_name.as_ptr(),
76 ))
77 }
78}
79
80/// Adds a new global variable of the specified type to the module in a specific address space.
81///
82/// This function wraps the `LLVMAddGlobalInAddressSpace` function from the LLVM core library. It creates a new global
83/// variable in the specified address space within the current module, with the provided type and name. Address spaces
84/// are used in LLVM to specify different memory regions for global variables, such as GPU memory or specialized
85/// hardware regions.
86///
87/// # Parameters
88///
89/// - `ty`: A reference to the `TypeRef` representing the type of the global variable.
90/// - `name`: A string slice (`&str`) representing the name of the global variable.
91/// - `address_space`: A reference to the `AddressSpace` where the global variable should be allocated.
92///
93/// # Returns
94///
95/// Returns a `ValueRef` representing the newly added global variable in the specified address space.
96#[must_use]
97pub fn add_global_in_address_space(
98 m: &ModuleRef,
99 ty: &TypeRef,
100 name: &str,
101 address_space: &AddressSpace,
102) -> ValueRef {
103 let c_name = CString::from(name);
104 unsafe {
105 ValueRef(core::LLVMAddGlobalInAddressSpace(
106 m.get_ref(),
107 ty.get_ref(),
108 c_name.as_ptr(),
109 ***address_space,
110 ))
111 }
112}
113
114/// Retrieves a global variable by its name from the module.
115///
116/// This function wraps the `LLVMGetNamedGlobal` function from the LLVM core library. It searches for a global
117/// variable with the specified name in the current module and returns it if found. If no global variable with the
118/// given name exists in the module, it returns `None`.
119///
120/// # Parameters
121///
122/// - `name`: A string slice (`&str`) representing the name of the global variable to search for.
123///
124/// # Returns
125///
126/// Returns an `Option<ValueRef>`:
127/// - `Some(ValueRef)` if a global variable with the specified name is found.
128/// - `None` if no global variable with the specified name exists in the module.
129#[must_use]
130pub fn get_named_global(m: &ModuleRef, name: &str) -> Option<ValueRef> {
131 let c_name = CString::from(name);
132 let global = unsafe { core::LLVMGetNamedGlobal(m.get_ref(), c_name.as_ptr()) };
133 if global.is_null() {
134 None
135 } else {
136 Some(ValueRef(global))
137 }
138}
139
140/// Retrieves the first global variable defined in the module.
141///
142/// This function wraps the `LLVMGetFirstGlobal` function from the LLVM core library. It returns the first global
143/// variable in the current module, which can be useful for iterating through all global variables in the module.
144///
145/// # Returns
146///
147/// Returns an `Option<ValueRef>`:
148/// - `Some(ValueRef)` if the module contains at least one global variable.
149/// - `None` if the module does not have any global variables.
150#[must_use]
151pub fn get_first_global(m: &ModuleRef) -> Option<ValueRef> {
152 let global = unsafe { core::LLVMGetFirstGlobal(m.get_ref()) };
153 if global.is_null() {
154 None
155 } else {
156 Some(ValueRef(global))
157 }
158}
159
160/// Retrieves the last global variable defined in the module.
161///
162/// This function wraps the `LLVMGetLastGlobal` function from the LLVM core library. It returns the last global
163/// variable in the current module, which can be useful for iterating through all global variables or accessing the
164/// most recently defined one.
165///
166/// # Returns
167///
168/// Returns an `Option<ValueRef>`:
169/// - `Some(ValueRef)` if the module contains at least one global variable.
170/// - `None` if the module does not have any global variables.
171#[must_use]
172pub fn get_last_global(m: &ModuleRef) -> Option<ValueRef> {
173 let global = unsafe { core::LLVMGetLastGlobal(m.get_ref()) };
174 if global.is_null() {
175 None
176 } else {
177 Some(ValueRef(global))
178 }
179}
180
181/// Retrieves the next global variable following the current one in the module.
182///
183/// This function wraps the `LLVMGetNextGlobal` function from the LLVM core library. It returns the global variable
184/// that comes after the current global variable in the module. This is useful for iterating through all global variables
185/// in a module.
186///
187/// # Returns
188///
189/// Returns an `Option<ValueRef>`:
190/// - `Some(ValueRef)` if there is another global variable following the current one.
191/// - `None` if the current global variable is the last one in the module.
192#[must_use]
193pub fn get_next_global(val: &ValueRef) -> Option<ValueRef> {
194 let global = unsafe { core::LLVMGetNextGlobal(val.get_ref()) };
195 if global.is_null() {
196 None
197 } else {
198 Some(ValueRef(global))
199 }
200}
201
202/// Retrieves the previous global variable preceding the current one in the module.
203///
204/// This function wraps the `LLVMGetPreviousGlobal` function from the LLVM core library. It returns the global variable
205/// that comes before the current global variable in the module. This is useful for iterating backward through all global
206/// variables in a module.
207///
208/// # Returns
209///
210/// Returns an `Option<ValueRef>`:
211/// - `Some(ValueRef)` if there is a global variable preceding the current one.
212/// - `None` if the current global variable is the first one in the module.
213#[must_use]
214pub fn get_previous_global(val: &ValueRef) -> Option<ValueRef> {
215 let global = unsafe { core::LLVMGetPreviousGlobal(val.get_ref()) };
216 if global.is_null() {
217 None
218 } else {
219 Some(ValueRef(global))
220 }
221}
222
223/// Deletes the specified global variable.
224///
225/// This function wraps the `LLVMDeleteGlobal` function from the LLVM core library. It removes the global variable
226/// represented by `ValueRef` from the module and deletes it. After this function is called, the global variable is no
227/// longer valid and cannot be used.
228///
229/// # Note
230///
231/// Once a global variable is deleted, it cannot be accessed or modified. Be cautious when deleting global variables
232/// to ensure that there are no further references to them.
233///
234/// # Example
235/// ```rust
236/// let global_var = module.add_global(&int32_type, "my_global");
237/// global_var.delete_global(); // Deletes the global variable
238/// ```
239pub fn delete_global(val: &ValueRef) {
240 unsafe {
241 core::LLVMDeleteGlobal(val.get_ref());
242 }
243}
244
245/// Get the initializer for a global variable.
246///
247/// This function wraps the `LLVMGetInitializer` function from the LLVM core library. It returns the initializer of the
248/// global variable represented by `ValueRef`. If the global variable has no initializer, the function returns `None`.
249/// The initializer is the constant value assigned to the global variable at the time of its definition.
250///
251/// # Returns
252///
253/// Returns an `Option<ValueRef>`:
254/// - `Some(ValueRef)` if the global variable has an initializer.
255/// - `None` if the global variable does not have an initializer.
256#[must_use]
257pub fn get_initializer(val: &ValueRef) -> Option<ValueRef> {
258 let initializer = unsafe { core::LLVMGetInitializer(val.get_ref()) };
259 if initializer.is_null() {
260 None
261 } else {
262 Some(ValueRef(initializer))
263 }
264}
265
266/// Sets the initializer for a global variable.
267///
268/// This function wraps the `LLVMSetInitializer` function from the LLVM core library. It assigns the provided constant value
269/// as the initializer for the global variable represented by `ValueRef`. The initializer is a constant value that the global
270/// variable will be set to when the program starts. Only constant values can be used as initializers for global variables.
271///
272/// # Parameters
273///
274/// - `constant_val`: A reference to the constant value (`ValueRef`) that will be used as the initializer for the global variable.
275pub fn set_initializer(val: &ValueRef, constant_val: &ValueRef) {
276 unsafe {
277 core::LLVMSetInitializer(val.get_ref(), constant_val.get_ref());
278 }
279}
280
281/// Determines if the global variable is thread-local.
282///
283/// This function wraps the `LLVMIsThreadLocal` function from the LLVM core library. It checks whether the global
284/// variable represented by `ValueRef` is marked as thread-local. A thread-local variable has a separate instance for each
285/// thread in a multi-threaded program, ensuring that threads do not share the same global variable.
286///
287/// # Returns
288///
289/// Returns `true` if the global variable is thread-local, otherwise returns `false`.
290#[must_use]
291pub fn is_thread_local(val: &ValueRef) -> bool {
292 unsafe { core::LLVMIsThreadLocal(val.get_ref()) != 0 }
293}
294
295/// Sets whether the global variable is thread-local.
296///
297/// This function wraps the `LLVMSetThreadLocal` function from the LLVM core library. It marks the global variable
298/// represented by `ValueRef` as either thread-local or not, based on the provided boolean value. A thread-local variable
299/// has a separate instance for each thread in a multi-threaded program, ensuring that threads do not share the same
300/// global variable.
301///
302/// # Parameters
303///
304/// - `is_thread_local`: A boolean value. If `true`, the global variable is marked as thread-local. If `false`, it is not thread-local.
305pub fn set_thread_local(val: &ValueRef, is_thread_local: bool) {
306 unsafe {
307 core::LLVMSetThreadLocal(val.get_ref(), *CInt::from(is_thread_local));
308 }
309}
310
311/// Determines if the global variable is a constant.
312///
313/// This function wraps the `LLVMIsGlobalConstant` function from the LLVM core library. It checks whether the global
314/// variable represented by `ValueRef` is marked as a constant. A global constant cannot be modified after its initialization
315/// and remains the same throughout the execution of the program.
316///
317/// # Returns
318///
319/// Returns `true` if the global variable is a constant, otherwise returns `false`.
320#[must_use]
321pub fn is_global_constant(val: &ValueRef) -> bool {
322 unsafe { core::LLVMIsGlobalConstant(val.get_ref()) != 0 }
323}
324
325/// Sets whether the global variable is a constant.
326///
327/// This function wraps the `LLVMSetGlobalConstant` function from the LLVM core library. It marks the global variable
328/// represented by `ValueRef` as either a constant or not, based on the provided boolean value. A global constant cannot
329/// be modified after its initialization and remains constant throughout the execution of the program.
330///
331/// # Parameters
332///
333/// - `is_constant`: A boolean value. If `true`, the global variable is marked as a constant. If `false`, it is not a constant.
334pub fn set_global_constant(val: &ValueRef, is_constant: bool) {
335 unsafe {
336 core::LLVMSetGlobalConstant(val.get_ref(), *CInt::from(is_constant));
337 }
338}
339
340/// Retrieves the thread-local storage (TLS) mode of the global variable.
341///
342/// This function wraps the `LLVMGetThreadLocalMode` function from the LLVM core library. It returns the thread-local
343/// mode of the global variable represented by `ValueRef`. The TLS mode defines how the thread-local variable is handled
344/// by the runtime and can affect performance and behavior in multi-threaded environments.
345///
346/// # Returns
347///
348/// Returns a `ThreadLocalMode` enum value representing the thread-local mode of the global variable:
349/// - `ThreadLocalMode::NotThreadLocal`: The global variable is not thread-local.
350/// - `ThreadLocalMode::GeneralDynamicTLSModel`: General dynamic TLS model.
351/// - `ThreadLocalMode::LocalDynamicTLSModel`: Local dynamic TLS model.
352/// - `ThreadLocalMode::InitialExecTLSModel`: Initial exec TLS model.
353/// - `ThreadLocalMode::LocalExecTLSModel`: Local exec TLS model.
354#[must_use]
355pub fn get_thread_local_mode(val: &ValueRef) -> ThreadLocalMode {
356 unsafe { core::LLVMGetThreadLocalMode(val.get_ref()).into() }
357}
358
359/// Sets the thread-local storage (TLS) mode for the global variable.
360///
361/// This function wraps the `LLVMSetThreadLocalMode` function from the LLVM core library. It configures the thread-local
362/// mode for the global variable represented by `ValueRef`. The TLS mode defines how the runtime handles the thread-local
363/// variable, influencing its performance and behavior in multi-threaded environments.
364///
365/// # Parameters
366///
367/// - `mode`: A `ThreadLocalMode` enum value representing the desired thread-local mode:
368/// - `ThreadLocalMode::NotThreadLocal`: The global variable is not thread-local.
369/// - `ThreadLocalMode::GeneralDynamicTLSModel`: General dynamic TLS model.
370/// - `ThreadLocalMode::LocalDynamicTLSModel`: Local dynamic TLS model.
371/// - `ThreadLocalMode::InitialExecTLSModel`: Initial exec TLS model.
372/// - `ThreadLocalMode::LocalExecTLSModel`: Local exec TLS model.
373pub fn set_thread_local_mode(val: &ValueRef, mode: ThreadLocalMode) {
374 unsafe {
375 core::LLVMSetThreadLocalMode(val.get_ref(), mode.into());
376 }
377}
378
379/// Determines if the global variable is externally initialized.
380///
381/// This function wraps the `LLVMIsExternallyInitialized` function from the LLVM core library. It checks whether
382/// the global variable represented by `ValueRef` is marked as externally initialized. A global variable that is externally
383/// initialized may have its initial value provided by external code, such as during dynamic linking.
384///
385/// # Returns
386///
387/// Returns `true` if the global variable is externally initialized, otherwise returns `false`.
388#[must_use]
389pub fn is_externally_initialized(val: &ValueRef) -> bool {
390 unsafe { core::LLVMIsExternallyInitialized(val.get_ref()) != 0 }
391}
392
393/// Sets whether the global variable is externally initialized.
394///
395/// This function wraps the `LLVMSetExternallyInitialized` function from the LLVM core library. It marks the global variable
396/// represented by `ValueRef` as externally initialized or not, based on the provided boolean value. Externally initialized
397/// global variables may receive their initial values from external code, such as during dynamic linking.
398///
399/// # Parameters
400///
401/// - `is_ext_init`: A boolean value. If `true`, the global variable is marked as externally initialized. If `false`, it is not externally initialized.
402pub fn set_externally_initialized(val: &ValueRef, is_ext_init: bool) {
403 unsafe {
404 core::LLVMSetExternallyInitialized(val.get_ref(), *CInt::from(is_ext_init));
405 }
406}