From 56635a8adfbbbc72c764830c0883794b511797c0 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 1 Sep 2024 16:12:23 +0200 Subject: [PATCH 1/3] Added basic implementations for global values --- Cargo.toml | 2 +- src/core/context.rs | 9 +- src/core/mod.rs | 14 +- src/core/module.rs | 16 +- src/core/types/mod.rs | 2 +- src/core/values/constants/global_values.rs | 240 +++++++++++++++++++++ src/core/values/constants/mod.rs | 1 + src/core/values/general.rs | 2 +- 8 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 src/core/values/constants/global_values.rs diff --git a/Cargo.toml b/Cargo.toml index f2587d7..6b68eb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "llvm-lib" -version = "0.6.0" +version = "0.6.1" authors = ["Evgeny Ukhanov "] description = "LLVM library with safe and flexibility in mind, without over complexity based on LLVM-C API" categories = ["compilers", "development-tools", "development-tools::build-utils"] diff --git a/src/core/context.rs b/src/core/context.rs index 2b79146..29d8fa3 100644 --- a/src/core/context.rs +++ b/src/core/context.rs @@ -766,14 +766,13 @@ impl GetRef for DiagnosticInfoRef { } impl DiagnosticInfoRef { - /// Return a string representation of the `DiagnosticInfo`. Use - /// [`crate::core::dispose_message`] (`LLVMDisposeMessage`) to free the string. + /// Return a string representation of the `DiagnosticInfo`. /// /// # Details /// /// This function wraps the `LLVMGetDiagInfoDescription` function from the LLVM core library. It retrieves a description /// of the diagnostic information represented by `self` as a `String`. The description provides a human-readable explanation - /// of the diagnostic. After obtaining the string, the memory must be freed using [`crate::core::dispose_message`]. + /// of the diagnostic. After obtaining the string, the memory is freed using `LLVMDisposeMessage`. /// /// # Returns /// @@ -783,7 +782,7 @@ impl DiagnosticInfoRef { /// /// # Safety /// - /// This function allocates memory for the string, which must be freed using [`crate::core::dispose_message`]. + /// This function allocates memory for the string, which is freed using `LLVMDisposeMessage`. #[must_use] pub fn get_description(&self) -> Option { unsafe { @@ -793,7 +792,7 @@ impl DiagnosticInfoRef { } let value = CStr::new(c_str).to_string(); // Dispose message - crate::core::dispose_message(c_str); + core::LLVMDisposeMessage(c_str); Some(value) } } diff --git a/src/core/mod.rs b/src/core/mod.rs index 23635b1..a0cd773 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -42,10 +42,16 @@ impl AddressSpace { } /// Dispose LLVM message -/// ## Safety -/// Common function to dispose allocated message -pub unsafe fn dispose_message(message: *mut libc::c_char) { - unsafe { core::LLVMDisposeMessage(message) } +/// +/// ## Panics +/// This function is purely informative and panics with a message about the call +/// being unavailable. Since there are no cases in which it can be called in +/// safe code. For raw access, if there is such a need, must be called +/// `LLVMDisposeMessage` directly. +pub fn dispose_message(_message: libc::c_char) { + unreachable!( + "LLVMDisposeMessage is unsafe adn restricted to operated to operate directly for safe code" + ); } /// LLVM version representation diff --git a/src/core/module.rs b/src/core/module.rs index f0bd22d..98a4931 100644 --- a/src/core/module.rs +++ b/src/core/module.rs @@ -95,6 +95,12 @@ impl NamedMetadataNodeRef { #[derive(Debug)] pub struct MetadataRef(LLVMMetadataRef); +impl From for MetadataRef { + fn from(metadata: LLVMMetadataRef) -> Self { + Self(metadata) + } +} + /// Represents flags that describe information about the module for use by /// an external entity e.g. the dynamic linker. #[allow(dead_code)] @@ -221,6 +227,12 @@ impl Drop for ModuleRef { } } +impl From for ModuleRef { + fn from(module: LLVMModuleRef) -> Self { + Self(module) + } +} + impl GetRef for ModuleRef { type RawRef = LLVMModuleRef; fn get_ref(&self) -> Self::RawRef { @@ -418,7 +430,7 @@ impl ModuleRef { } else { unsafe { let error = CStr::new(error_message).to_string(); - crate::core::dispose_message(error_message); + core::LLVMDisposeMessage(error_message); Err(error) } } @@ -433,7 +445,7 @@ impl ModuleRef { return None; } let result = CStr::new(c_str).to_string(); - crate::core::dispose_message(c_str); + core::LLVMDisposeMessage(c_str); Some(result) } } diff --git a/src/core/types/mod.rs b/src/core/types/mod.rs index 40527b0..e70d32a 100644 --- a/src/core/types/mod.rs +++ b/src/core/types/mod.rs @@ -226,7 +226,7 @@ impl TypeRef { return String::new(); } let rust_string = CStr::new(c_str).to_string(); - super::dispose_message(c_str); + core::LLVMDisposeMessage(c_str); rust_string } } diff --git a/src/core/values/constants/global_values.rs b/src/core/values/constants/global_values.rs new file mode 100644 index 0000000..3732572 --- /dev/null +++ b/src/core/values/constants/global_values.rs @@ -0,0 +1,240 @@ +use super::ValueRef; +use crate::core::module::{MetadataRef, ModuleRef}; +use crate::core::types::TypeRef; +use crate::{CStr, CString, CUint, GetRef}; +use llvm_sys::core; +use llvm_sys::prelude::LLVMValueMetadataEntry; + +/// Wrapper for `LLVMValueMetadataEntry` +#[derive(Debug)] +pub struct ValueMetadataEntry(LLVMValueMetadataEntry); + +impl From for ValueMetadataEntry { + fn from(value: LLVMValueMetadataEntry) -> Self { + ValueMetadataEntry(value) + } +} + +impl GetRef for ValueMetadataEntry { + type RawRef = LLVMValueMetadataEntry; + fn get_ref(&self) -> Self::RawRef { + self.0 + } +} + +impl ValueRef { + /// Get the module that contains the global value. + /// + /// @see llvm::GlobalValue::getParent() + pub fn get_global_parent(&self) -> ModuleRef { + unsafe { ModuleRef::from(core::LLVMGetGlobalParent(self.0)) } + } + + /// Determine if the global value is a declaration. + /// + /// @see llvm::GlobalValue::isDeclaration() + pub fn is_declaration(&self) -> bool { + unsafe { core::LLVMIsDeclaration(self.0) != 0 } + } + + /// Get the linkage of the global value. + /// + /// @see llvm::GlobalValue::getLinkage() + pub fn get_linkage(&self) -> LLVMLinkage { + unsafe { core::LLVMGetLinkage(self.0) } + } + + /// Set the linkage of the global value. + /// + /// @see llvm::GlobalValue::setLinkage() + pub fn set_linkage(&self, linkage: LLVMLinkage) { + unsafe { core::LLVMSetLinkage(self.0, linkage) } + } + + /// Get the section of the global value. + /// + /// @see llvm::GlobalValue::getSection() + pub fn get_section(&self) -> Option { + unsafe { + let section = core::LLVMGetSection(self.0); + if section.is_null() { + None + } else { + Some(CStr::new(section).to_string()) + } + } + } + + /// Set the section of the global value. + /// + /// @see llvm::GlobalValue::setSection() + pub fn set_section(&self, section: &str) { + let c_section = CString::from(section); + unsafe { + core::LLVMSetSection(self.0, c_section.as_ptr()); + } + } + + /// Get the visibility of the global value. + /// + /// @see llvm::GlobalValue::getVisibility() + pub fn get_visibility(&self) -> Visibility { + unsafe { core::LLVMGetVisibility(self.0) } + } + + /// Set the visibility of the global value. + /// + /// @see llvm::GlobalValue::setVisibility() + pub fn set_visibility(&self, visibility: Visibility) { + unsafe { + core::LLVMSetVisibility(self.0, visibility); + } + } + + /// Get the DLL storage class of a global value. + /// + /// @see llvm::GlobalValue::getDLLStorageClass() + pub fn get_dll_storage_class(&self) -> DLLStorageClass { + unsafe { core::LLVMGetDLLStorageClass(self.0) } + } + + /// Set the DLL storage class of a global value. + /// + /// @see llvm::GlobalValue::setDLLStorageClass() + pub fn set_dll_storage_class(&self, class: DLLStorageClass) { + unsafe { + core::LLVMSetDLLStorageClass(self.0, class); + } + } + + /// Get the unnamed address of a global value. + /// + /// @see llvm::GlobalValue::getUnnamedAddr() + pub fn get_unnamed_address(&self) -> UnnamedAddr { + unsafe { core::LLVMGetUnnamedAddress(self.0) } + } + + /// Set the unnamed address of a global value. + /// + /// @see llvm::GlobalValue::setUnnamedAddr() + pub fn set_unnamed_address(&self, unnamed_addr: UnnamedAddr) { + unsafe { + core::LLVMSetUnnamedAddress(self.0, unnamed_addr); + } + } + + /// Returns the "value type" of a global value. This differs from the formal + /// type of a global value, which is always a pointer type. + /// + /// @see llvm::GlobalValue::getValueType() + pub fn get_value_type(&self) -> TypeRef { + unsafe { TypeRef::from(core::LLVMGlobalGetValueType(self.0)) } + } + + /// Obtain the preferred alignment of the value. + /// + /// @see llvm::AllocaInst::getAlignment() + /// @see llvm::LoadInst::getAlignment() + /// @see llvm::StoreInst::getAlignment() + /// @see llvm::AtomicRMWInst::setAlignment() + /// @see llvm::AtomicCmpXchgInst::setAlignment() + /// @see llvm::GlobalValue::getAlignment() + pub fn get_alignment(&self) -> u32 { + unsafe { core::LLVMGetAlignment(self.0) as u32 } + } + + /// Set the preferred alignment of the value. + /// + /// @see llvm::AllocaInst::setAlignment() + /// @see llvm::LoadInst::setAlignment() + /// @see llvm::StoreInst::setAlignment() + /// @see llvm::AtomicRMWInst::setAlignment() + /// @see llvm::AtomicCmpXchgInst::setAlignment() + /// @see llvm::GlobalValue::setAlignment() + pub fn set_alignment(&self, bytes: u32) { + unsafe { + core::LLVMSetAlignment(self.0, bytes as c_uint); + } + } + + /// Sets a metadata attachment, erasing the existing metadata attachment if + /// it already exists for the given kind. + /// + /// @see llvm::GlobalObject::setMetadata() + pub fn global_set_metadata(&self, kind: u32, md: LLVMMetadataRef) { + unsafe { + core::LLVMGlobalSetMetadata(self.0, kind, md); + } + } + + /// Erases a metadata attachment of the given kind if it exists. + /// + /// @see llvm::GlobalObject::eraseMetadata() + pub fn global_erase_metadata(&self, kind: u32) { + unsafe { + core::LLVMGlobalEraseMetadata(self.0, kind); + } + } + + /// Removes all metadata attachments from this value. + /// + /// @see llvm::GlobalObject::clearMetadata() + pub fn global_clear_metadata(&self) { + unsafe { + core::LLVMGlobalClearMetadata(self.0); + } + } + + /// Destroys value metadata entries. + /// + /// ## Panics + /// This function is purely informative and panics with a message about the call + /// being unavailable. Since there are no cases in which it can be called in + /// safe code. For raw access, if there is such a need, must be called + /// `LLVMDisposeValueMetadataEntries` directly. + pub fn dispose_value_metadata_entries(_entries: Vec) { + unreachable!("LLVMDisposeValueMetadataEntries is unsafe adn restricted to operated to operate directly for safe code"); + } + + /// Retrieves an array of metadata entries representing the metadata attached to + /// this value. The caller is responsible for freeing this array by calling + /// `LLVMDisposeValueMetadataEntries`. + /// + /// @see llvm::GlobalObject::getAllMetadata() + pub fn global_copy_all_metadata(&self) -> Vec { + let mut num_entries: usize = 0; + let entries_ptr = unsafe { core::LLVMGlobalCopyAllMetadata(self.0, &mut num_entries) }; + + if entries_ptr.is_null() { + return Vec::new(); + } + let entries_slice = unsafe { std::slice::from_raw_parts(entries_ptr, num_entries) }; + + let entries = entries_slice + .iter() + .map(|&entry| ValueMetadataEntry::from(entry)) + .collect::>(); + + // Free the memory allocated by `LLVMGlobalCopyAllMetadata` + unsafe { + core::LLVMDisposeValueMetadataEntries(entries_ptr); + } + + entries + } + + /// Returns the kind of a value metadata entry at a specific index. + pub fn get_kind(&self, index: u32) -> u32 { + unsafe { core::LLVMValueMetadataEntriesGetKind(self.0, index as c_uint) as u32 } + } + + /// Returns the underlying metadata node of a value metadata entry at a specific index. + pub fn get_metadata(&self, index: u32) -> MetadataRef { + unsafe { + MetadataRef::from(core::LLVMValueMetadataEntriesGetMetadata( + self.0, + *CUint::from(index), + )) + } + } +} diff --git a/src/core/values/constants/mod.rs b/src/core/values/constants/mod.rs index 387f79d..0877f3b 100644 --- a/src/core/values/constants/mod.rs +++ b/src/core/values/constants/mod.rs @@ -3,6 +3,7 @@ pub mod composite; pub mod expressions; +mod global_values; pub mod scalar; use super::ValueRef; diff --git a/src/core/values/general.rs b/src/core/values/general.rs index d1bb72d..5e9dad0 100644 --- a/src/core/values/general.rs +++ b/src/core/values/general.rs @@ -141,7 +141,7 @@ impl ValueRef { return None; } let result = CStr::new(c_str).to_string(); - crate::core::dispose_message(c_str); + core::LLVMDisposeMessage(c_str); Some(result) } } From 33fabc2da16e9985dae97456ce1c519945a68ce3 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 1 Sep 2024 17:01:23 +0200 Subject: [PATCH 2/3] Added Linkage and Visibility --- src/core/mod.rs | 129 ++++++++++++++++++++- src/core/values/constants/global_values.rs | 29 ++--- 2 files changed, 135 insertions(+), 23 deletions(-) diff --git a/src/core/mod.rs b/src/core/mod.rs index a0cd773..ab95954 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,5 +1,7 @@ use crate::CUint; -use llvm_sys::{core, LLVMIntPredicate, LLVMOpcode, LLVMRealPredicate}; +use llvm_sys::{ + core, LLVMIntPredicate, LLVMLinkage, LLVMOpcode, LLVMRealPredicate, LLVMVisibility, +}; use std::fmt::Display; use std::ops::Deref; @@ -565,3 +567,128 @@ impl From for LLVMRealPredicate { } } } + +/// Represents the linkage types in LLVM for global values. +/// Linkage types determine the visibility and behavior of symbols across different modules and within the same module. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Linkage { + /// Externally visible function or variable. Can be linked from another module. + ExternalLinkage, + /// Similar to `ExternalLinkage`, but the symbol may be discarded if not used. + AvailableExternallyLinkage, + /// Keeps one copy of the function or variable when linking, discarding others. + LinkOnceAnyLinkage, + /// Similar to `LinkOnceAnyLinkage`, but the symbol cannot be discarded. + LinkOnceODRLinkage, + /// Same as `LinkOnceODRLinkage`, but with hidden visibility. + LinkOnceODRAutoHideLinkage, + /// Keeps one copy, discarding others, but prefer the local copy. + WeakAnyLinkage, + /// Similar to `WeakAnyLinkage`, but ensures that the symbol is unique and is emitted only once. + WeakODRLinkage, + /// Appending linkage: when linked, multiple definitions of the same variable are concatenated. + AppendingLinkage, + /// Local to the translation unit, not visible outside of it. + InternalLinkage, + /// Similar to `InternalLinkage`, but prevents inlining and other optimizations. + PrivateLinkage, + /// Indicates that the global value should be imported from a DLL. + DLLImportLinkage, + /// Indicates that the global value should be exported to a DLL. + DLLExportLinkage, + /// The global variable or function is merged into the program only if it is used. + ExternalWeakLinkage, + /// A special linkage type used internally by the linker. + GhostLinkage, + /// Common linkage for uninitialized global variables. + CommonLinkage, + /// Linker private linkage, used to indicate a symbol that is internal to the module. + LinkerPrivateLinkage, + /// Weak version of `LinkerPrivateLinkage`. + LinkerPrivateWeakLinkage, +} + +impl From for Linkage { + fn from(linkage: LLVMLinkage) -> Self { + match linkage { + LLVMLinkage::LLVMExternalLinkage => Self::ExternalLinkage, + LLVMLinkage::LLVMAvailableExternallyLinkage => Self::AvailableExternallyLinkage, + LLVMLinkage::LLVMLinkOnceAnyLinkage => Self::LinkOnceAnyLinkage, + LLVMLinkage::LLVMLinkOnceODRLinkage => Self::LinkOnceODRLinkage, + LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage => Self::LinkOnceODRAutoHideLinkage, + LLVMLinkage::LLVMWeakAnyLinkage => Self::WeakAnyLinkage, + LLVMLinkage::LLVMWeakODRLinkage => Self::WeakODRLinkage, + LLVMLinkage::LLVMAppendingLinkage => Self::AppendingLinkage, + LLVMLinkage::LLVMInternalLinkage => Self::InternalLinkage, + LLVMLinkage::LLVMPrivateLinkage => Self::PrivateLinkage, + LLVMLinkage::LLVMDLLImportLinkage => Self::DLLImportLinkage, + LLVMLinkage::LLVMDLLExportLinkage => Self::DLLExportLinkage, + LLVMLinkage::LLVMExternalWeakLinkage => Self::ExternalWeakLinkage, + LLVMLinkage::LLVMGhostLinkage => Self::GhostLinkage, + LLVMLinkage::LLVMCommonLinkage => Self::CommonLinkage, + LLVMLinkage::LLVMLinkerPrivateLinkage => Self::LinkerPrivateLinkage, + LLVMLinkage::LLVMLinkerPrivateWeakLinkage => Self::LinkerPrivateWeakLinkage, + } + } +} + +impl From for LLVMLinkage { + fn from(linkage: Linkage) -> Self { + match linkage { + Linkage::ExternalLinkage => Self::LLVMExternalLinkage, + Linkage::AvailableExternallyLinkage => Self::LLVMAvailableExternallyLinkage, + Linkage::LinkOnceAnyLinkage => Self::LLVMLinkOnceAnyLinkage, + Linkage::LinkOnceODRLinkage => Self::LLVMLinkOnceODRLinkage, + Linkage::LinkOnceODRAutoHideLinkage => Self::LLVMLinkOnceODRAutoHideLinkage, + Linkage::WeakAnyLinkage => Self::LLVMWeakAnyLinkage, + Linkage::WeakODRLinkage => Self::LLVMWeakODRLinkage, + Linkage::AppendingLinkage => Self::LLVMAppendingLinkage, + Linkage::InternalLinkage => Self::LLVMInternalLinkage, + Linkage::PrivateLinkage => Self::LLVMPrivateLinkage, + Linkage::DLLImportLinkage => Self::LLVMDLLImportLinkage, + Linkage::DLLExportLinkage => Self::LLVMDLLExportLinkage, + Linkage::ExternalWeakLinkage => Self::LLVMExternalWeakLinkage, + Linkage::GhostLinkage => Self::LLVMGhostLinkage, + Linkage::CommonLinkage => Self::LLVMCommonLinkage, + Linkage::LinkerPrivateLinkage => Self::LLVMLinkerPrivateLinkage, + Linkage::LinkerPrivateWeakLinkage => Self::LLVMLinkerPrivateWeakLinkage, + } + } +} + +/// `Visibility` is an enumeration in LLVM that represents the +/// visibility of global values such as functions and global +/// variables. Visibility determines how symbols are treated by +/// the linker and whether they can be seen by other modules or +/// shared libraries. +/// Generally `Visibility` represent access to the symbol after `Linkage`. +/// Useful to compose `Linkage` and `Visibility` to define the symbol behavior. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Visibility { + /// Default visibility. The symbol is visible to other modules. + DefaultVisibility, + /// Hidden visibility. The symbol is not visible to other modules or shared libraries. + HiddenVisibility, + /// Protected visibility. The symbol is visible to other modules but cannot be overridden. + ProtectedVisibility, +} + +impl From for Visibility { + fn from(visibility: LLVMVisibility) -> Self { + match visibility { + LLVMVisibility::LLVMDefaultVisibility => Self::DefaultVisibility, + LLVMVisibility::LLVMHiddenVisibility => Self::HiddenVisibility, + LLVMVisibility::LLVMProtectedVisibility => Self::ProtectedVisibility, + } + } +} + +impl From for LLVMVisibility { + fn from(visibility: Visibility) -> Self { + match visibility { + Visibility::DefaultVisibility => Self::LLVMDefaultVisibility, + Visibility::HiddenVisibility => Self::LLVMHiddenVisibility, + Visibility::ProtectedVisibility => Self::LLVMProtectedVisibility, + } + } +} diff --git a/src/core/values/constants/global_values.rs b/src/core/values/constants/global_values.rs index 3732572..617dd2f 100644 --- a/src/core/values/constants/global_values.rs +++ b/src/core/values/constants/global_values.rs @@ -1,6 +1,7 @@ use super::ValueRef; use crate::core::module::{MetadataRef, ModuleRef}; use crate::core::types::TypeRef; +use crate::core::{Linkage, Visibility}; use crate::{CStr, CString, CUint, GetRef}; use llvm_sys::core; use llvm_sys::prelude::LLVMValueMetadataEntry; @@ -24,36 +25,26 @@ impl GetRef for ValueMetadataEntry { impl ValueRef { /// Get the module that contains the global value. - /// - /// @see llvm::GlobalValue::getParent() pub fn get_global_parent(&self) -> ModuleRef { unsafe { ModuleRef::from(core::LLVMGetGlobalParent(self.0)) } } /// Determine if the global value is a declaration. - /// - /// @see llvm::GlobalValue::isDeclaration() pub fn is_declaration(&self) -> bool { unsafe { core::LLVMIsDeclaration(self.0) != 0 } } /// Get the linkage of the global value. - /// - /// @see llvm::GlobalValue::getLinkage() - pub fn get_linkage(&self) -> LLVMLinkage { - unsafe { core::LLVMGetLinkage(self.0) } + pub fn get_linkage(&self) -> Linkage { + unsafe { crate::core::Linkage::from(core::LLVMGetLinkage(self.0)) } } /// Set the linkage of the global value. - /// - /// @see llvm::GlobalValue::setLinkage() - pub fn set_linkage(&self, linkage: LLVMLinkage) { - unsafe { core::LLVMSetLinkage(self.0, linkage) } + pub fn set_linkage(&self, linkage: Linkage) { + unsafe { core::LLVMSetLinkage(self.0, linkage.into()) } } /// Get the section of the global value. - /// - /// @see llvm::GlobalValue::getSection() pub fn get_section(&self) -> Option { unsafe { let section = core::LLVMGetSection(self.0); @@ -66,8 +57,6 @@ impl ValueRef { } /// Set the section of the global value. - /// - /// @see llvm::GlobalValue::setSection() pub fn set_section(&self, section: &str) { let c_section = CString::from(section); unsafe { @@ -76,18 +65,14 @@ impl ValueRef { } /// Get the visibility of the global value. - /// - /// @see llvm::GlobalValue::getVisibility() pub fn get_visibility(&self) -> Visibility { - unsafe { core::LLVMGetVisibility(self.0) } + unsafe { crate::core::Visibility::from(core::LLVMGetVisibility(self.0)) } } /// Set the visibility of the global value. - /// - /// @see llvm::GlobalValue::setVisibility() pub fn set_visibility(&self, visibility: Visibility) { unsafe { - core::LLVMSetVisibility(self.0, visibility); + core::LLVMSetVisibility(self.0, visibility.into()); } } From d100afb32057cd547cf556bbb49d6e037a4adcee Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 1 Sep 2024 23:16:03 +0200 Subject: [PATCH 3/3] Added documentation --- src/core/mod.rs | 88 ++++- src/core/module.rs | 9 +- src/core/values/constants/global_values.rs | 395 ++++++++++++++++++--- src/core/values/constants/mod.rs | 2 +- 4 files changed, 441 insertions(+), 53 deletions(-) diff --git a/src/core/mod.rs b/src/core/mod.rs index ab95954..6590564 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,6 +1,7 @@ use crate::CUint; use llvm_sys::{ - core, LLVMIntPredicate, LLVMLinkage, LLVMOpcode, LLVMRealPredicate, LLVMVisibility, + core, LLVMDLLStorageClass, LLVMIntPredicate, LLVMLinkage, LLVMOpcode, LLVMRealPredicate, + LLVMUnnamedAddr, LLVMVisibility, }; use std::fmt::Display; use std::ops::Deref; @@ -570,7 +571,7 @@ impl From for LLVMRealPredicate { /// Represents the linkage types in LLVM for global values. /// Linkage types determine the visibility and behavior of symbols across different modules and within the same module. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Linkage { /// Externally visible function or variable. Can be linked from another module. ExternalLinkage, @@ -663,7 +664,7 @@ impl From for LLVMLinkage { /// shared libraries. /// Generally `Visibility` represent access to the symbol after `Linkage`. /// Useful to compose `Linkage` and `Visibility` to define the symbol behavior. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Visibility { /// Default visibility. The symbol is visible to other modules. DefaultVisibility, @@ -692,3 +693,84 @@ impl From for LLVMVisibility { } } } + +/// Represents the DLL storage classes in LLVM, that specifies how a global value, +/// such as a function or global variable, should be treated with respect to +/// dynamic link libraries (DLLs) on platforms like Windows. The `DLLStorageClass` +/// controls whether a symbol should be imported from a DLL, exported to a DLL, or +/// treated as a normal global symbol. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum DLLStorageClass { + /// `DefaultStorageClass`: The default storage class. The symbol is not specifically marked for import or export + /// from a DLL. It is treated as a normal global symbol. + DefaultStorageClass, + /// `DLLImportStorageClass`: Specifies that the symbol should be imported from a DLL. This is used when you want + /// to use a function or variable that is defined in another DLL. The linker will ensure that the symbol is correctly + /// imported at runtime. + DLLImportStorageClass, + /// `DLLExportStorageClass`: Specifies that the symbol should be exported to a DLL. This is used when you want to make + /// a function or variable available for use by other modules or executables. The linker will ensure that the symbol is + /// correctly exported and accessible to other programs. + DLLExportStorageClass, +} + +impl From for LLVMDLLStorageClass { + fn from(storage_class: DLLStorageClass) -> Self { + match storage_class { + DLLStorageClass::DefaultStorageClass => Self::LLVMDefaultStorageClass, + DLLStorageClass::DLLImportStorageClass => Self::LLVMDLLImportStorageClass, + DLLStorageClass::DLLExportStorageClass => Self::LLVMDLLExportStorageClass, + } + } +} + +impl From for DLLStorageClass { + fn from(storage_class: LLVMDLLStorageClass) -> Self { + match storage_class { + LLVMDLLStorageClass::LLVMDefaultStorageClass => Self::DefaultStorageClass, + LLVMDLLStorageClass::LLVMDLLImportStorageClass => Self::DLLImportStorageClass, + LLVMDLLStorageClass::LLVMDLLExportStorageClass => Self::DLLExportStorageClass, + } + } +} + +/// Represents the unnamed address attribute for global values in LLVM. +/// +/// `UnnamedAddr` is an enumeration that specifies whether a global variable or function's address is significant. +/// This can help LLVM's optimizer determine whether it can merge or duplicate global values with identical content, +/// potentially reducing code size or improving performance. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum UnnamedAddr { + /// `NoUnnamedAddr`: The address of the global value is significant, and it must be unique. + /// The global variable or function cannot be merged with others, even if they have the same content. + /// This is the default behavior for most global values. + NoUnnamedAddr, + /// `LocalUnnamedAddr`: The address of the global value is not significant within the module, allowing the optimizer + /// to merge or duplicate global values with the same content. However, the address is still unique within the module. + /// This is useful for variables or functions that are only accessed within the same module and do not need a unique address. + LocalUnnamedAddr, + /// `GlobalUnnamedAddr`: The address of the global value is not significant across the entire program, allowing the optimizer + /// to freely merge or duplicate global values with identical content across different modules. + /// This can lead to more aggressive optimizations and is useful for constants or functions that do not rely on having a unique address. + GlobalUnnamedAddr, +} + +impl From for LLVMUnnamedAddr { + fn from(unnamed_addr: UnnamedAddr) -> Self { + match unnamed_addr { + UnnamedAddr::NoUnnamedAddr => Self::LLVMNoUnnamedAddr, + UnnamedAddr::LocalUnnamedAddr => Self::LLVMLocalUnnamedAddr, + UnnamedAddr::GlobalUnnamedAddr => Self::LLVMGlobalUnnamedAddr, + } + } +} + +impl From for UnnamedAddr { + fn from(unnamed_addr: LLVMUnnamedAddr) -> Self { + match unnamed_addr { + LLVMUnnamedAddr::LLVMNoUnnamedAddr => Self::NoUnnamedAddr, + LLVMUnnamedAddr::LLVMLocalUnnamedAddr => Self::LocalUnnamedAddr, + LLVMUnnamedAddr::LLVMGlobalUnnamedAddr => Self::GlobalUnnamedAddr, + } + } +} diff --git a/src/core/module.rs b/src/core/module.rs index 98a4931..b6830a3 100644 --- a/src/core/module.rs +++ b/src/core/module.rs @@ -92,7 +92,7 @@ impl NamedMetadataNodeRef { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MetadataRef(LLVMMetadataRef); impl From for MetadataRef { @@ -101,6 +101,13 @@ impl From for MetadataRef { } } +impl GetRef for MetadataRef { + type RawRef = LLVMMetadataRef; + fn get_ref(&self) -> Self::RawRef { + self.0 + } +} + /// Represents flags that describe information about the module for use by /// an external entity e.g. the dynamic linker. #[allow(dead_code)] diff --git a/src/core/values/constants/global_values.rs b/src/core/values/constants/global_values.rs index 617dd2f..1968f7b 100644 --- a/src/core/values/constants/global_values.rs +++ b/src/core/values/constants/global_values.rs @@ -1,7 +1,7 @@ use super::ValueRef; use crate::core::module::{MetadataRef, ModuleRef}; use crate::core::types::TypeRef; -use crate::core::{Linkage, Visibility}; +use crate::core::{DLLStorageClass, Linkage, UnnamedAddr, Visibility}; use crate::{CStr, CString, CUint, GetRef}; use llvm_sys::core; use llvm_sys::prelude::LLVMValueMetadataEntry; @@ -12,7 +12,7 @@ pub struct ValueMetadataEntry(LLVMValueMetadataEntry); impl From for ValueMetadataEntry { fn from(value: LLVMValueMetadataEntry) -> Self { - ValueMetadataEntry(value) + Self(value) } } @@ -25,26 +25,90 @@ impl GetRef for ValueMetadataEntry { impl ValueRef { /// Get the module that contains the global value. + /// + /// ## Details + /// + /// Retrieves the parent module of a global value. + /// + /// This function wraps the `LLVMGetGlobalParent` function from the LLVM core library. It returns the `ModuleRef` + /// representing the parent module in which the global value represented by `self` is defined. The parent module + /// contains all the global values (such as functions and global variables) that are part of a given LLVM module. + /// + /// # Returns + /// + /// Returns a `ModuleRef` representing the parent module of the global value. + #[must_use] pub fn get_global_parent(&self) -> ModuleRef { unsafe { ModuleRef::from(core::LLVMGetGlobalParent(self.0)) } } /// Determine if the global value is a declaration. + /// + /// ## Details + /// + /// Checks if the global value is a declaration. + /// + /// This function wraps the `LLVMIsDeclaration` function from the LLVM core library. It determines whether + /// the global value represented by `self` is merely a declaration (i.e., it declares the existence of a symbol + /// but does not define it). Declarations are often used to reference functions or variables that are defined + /// in another module or later in the same module. + /// + /// # Returns + /// + /// Returns `true` if the global value is a declaration, otherwise returns `false`. + #[must_use] pub fn is_declaration(&self) -> bool { unsafe { core::LLVMIsDeclaration(self.0) != 0 } } /// Get the linkage of the global value. + /// + /// ## Details + /// + /// Sets the linkage type for a global value. + /// + /// This function wraps the `LLVMSetLinkage` function from the LLVM core library. It configures the linkage type + /// for the global value represented by `self`. The linkage type determines how the symbol is treated during the + /// linking process, particularly in relation to how it can be combined with other symbols and whether it is visible + /// outside of the module. + /// + /// # Parameters + /// + /// - `linkage`: A `Linkage` enum value that specifies the linkage type for the global value. Common linkage types include: + /// - `ExternalLinkage`: The symbol is visible to other modules and can be linked against. + /// - `InternalLinkage`: The symbol is only visible within the current module. + /// - `PrivateLinkage`: The symbol is local to the file and not exposed to other modules. + /// - `LinkOnceODRLinkage`: Ensures that the symbol is defined only once across all modules, complying with the One Definition Rule (ODR). + #[must_use] pub fn get_linkage(&self) -> Linkage { unsafe { crate::core::Linkage::from(core::LLVMGetLinkage(self.0)) } } /// Set the linkage of the global value. + /// + /// ## Details + /// + /// pub fn set_linkage(&self, linkage: Linkage) { unsafe { core::LLVMSetLinkage(self.0, linkage.into()) } } /// Get the section of the global value. + /// + /// ## Details + /// + /// Retrieves the section name in which a global value is placed. + /// + /// This function wraps the `LLVMGetSection` function from the LLVM core library. It returns the name of the section + /// where the global value represented by `self` is placed. Sections are used to organize global values in the object file, + /// allowing the linker and loader to place related values together or handle them in a specific way. + /// + /// # Returns + /// + /// Returns an `Option`: + /// - `Some(String)` containing the name of the section if the global value is placed in a specific section. + /// - `None` if the global value is not associated with any section. + #[must_use] pub fn get_section(&self) -> Option { unsafe { let section = core::LLVMGetSection(self.0); @@ -57,6 +121,18 @@ impl ValueRef { } /// Set the section of the global value. + /// + /// ## Details + /// + /// Sets the section in which a global value should be placed. + /// + /// This function wraps the `LLVMSetSection` function from the LLVM core library. It specifies the section name + /// for the global value represented by `self`. Sections are used to organize global values in the object file, allowing + /// the linker and loader to place related values together or handle them in a specific way. + /// + /// # Parameters + /// + /// - `section`: A string slice (`&str`) representing the name of the section where the global value should be placed. pub fn set_section(&self, section: &str) { let c_section = CString::from(section); unsafe { @@ -65,11 +141,42 @@ impl ValueRef { } /// Get the visibility of the global value. + /// + /// ## Details + /// + /// Retrieves the visibility attribute of a global value. + /// + /// This function wraps the `LLVMGetVisibility` function from the LLVM core library. It returns the visibility + /// attribute of the global value represented by `self`. The visibility attribute determines how the symbol is + /// treated by the linker and whether it can be seen by other modules or shared libraries. + /// + /// # Returns + /// + /// Returns a `Visibility` enum value representing the visibility attribute of the global value: + /// - `DefaultVisibility`: The symbol is visible to other modules. + /// - `HiddenVisibility`: The symbol is not visible to other modules or shared libraries. + /// - `ProtectedVisibility`: The symbol is visible to other modules but cannot be overridden. + #[must_use] pub fn get_visibility(&self) -> Visibility { unsafe { crate::core::Visibility::from(core::LLVMGetVisibility(self.0)) } } /// Set the visibility of the global value. + /// + /// ## Details + /// + /// Sets the visibility attribute for a global value. + /// + /// This function wraps the `LLVMSetVisibility` function from the LLVM core library. It configures the visibility + /// attribute for the global value represented by `self`. The visibility attribute determines how the symbol is + /// treated by the linker and whether it can be seen by other modules or shared libraries. + /// + /// # Parameters + /// + /// - `visibility`: A `Visibility` enum value that specifies the visibility of the global value: + /// - `DefaultVisibility`: The symbol is visible to other modules. + /// - `HiddenVisibility`: The symbol is not visible to other modules or shared libraries. + /// - `ProtectedVisibility`: The symbol is visible to other modules but cannot be overridden. pub fn set_visibility(&self, visibility: Visibility) { unsafe { core::LLVMSetVisibility(self.0, visibility.into()); @@ -78,92 +185,199 @@ impl ValueRef { /// Get the DLL storage class of a global value. /// - /// @see llvm::GlobalValue::getDLLStorageClass() + /// ## Details + /// + /// Retrieves the DLL storage class of a global value. + /// + /// This function wraps the `LLVMGetDLLStorageClass` function from the LLVM core library. It returns the + /// `DLLStorageClass` of the global value represented by `self`. The DLL storage class determines how the global + /// value is treated in relation to dynamic link libraries (DLLs) on platforms like Windows. + /// + /// # Returns + /// + /// Returns a `DLLStorageClass` enum value representing the DLL storage class of the global value: + /// - `DefaultStorageClass`: The symbol is treated as a normal global symbol, not specifically marked for import or export from a DLL. + /// - `DLLImportStorageClass`: The symbol is imported from a DLL. + /// - `DLLExportStorageClass`: The symbol is exported to a DLL. + #[must_use] pub fn get_dll_storage_class(&self) -> DLLStorageClass { - unsafe { core::LLVMGetDLLStorageClass(self.0) } + unsafe { DLLStorageClass::from(core::LLVMGetDLLStorageClass(self.0)) } } /// Set the DLL storage class of a global value. /// - /// @see llvm::GlobalValue::setDLLStorageClass() + /// ## Details + /// + /// Sets the DLL storage class for a global value. + /// + /// This function wraps the `LLVMSetDLLStorageClass` function from the LLVM core library. It configures the DLL storage class + /// for the global value represented by `self`. The `DLLStorageClass` attribute determines how the global value is treated + /// in relation to dynamic link libraries (DLLs) on platforms like Windows. + /// + /// # Parameters + /// + /// - `class`: A `DLLStorageClass` enum value that specifies the DLL storage class for the global value. + /// - `DefaultStorageClass`: The symbol is treated as a normal global symbol, not specifically marked for import or export from a DLL. + /// - `DLLImportStorageClass`: The symbol is imported from a DLL. + /// - `DLLExportStorageClass`: The symbol is exported to a DLL. pub fn set_dll_storage_class(&self, class: DLLStorageClass) { unsafe { - core::LLVMSetDLLStorageClass(self.0, class); + core::LLVMSetDLLStorageClass(self.0, class.into()); } } /// Get the unnamed address of a global value. /// - /// @see llvm::GlobalValue::getUnnamedAddr() + /// ## Details + /// + /// Retrieves the unnamed address attribute of a global value. + /// + /// This function wraps the `LLVMGetUnnamedAddress` function from the LLVM core library. It returns the + /// `UnnamedAddr` attribute of the global value represented by `self`. This attribute specifies whether the address + /// of the global value is significant, which can influence certain optimizations in LLVM. + /// + /// # Returns + /// + /// Returns an `UnnamedAddr` enum value representing the unnamed address attribute of the global value: + /// - `NoUnnamedAddr`: The address of the global value is significant and must be unique. + /// - `LocalUnnamedAddr`: The address is not significant within the module, allowing certain optimizations. + /// - `GlobalUnnamedAddr`: The address is not significant across the entire program, enabling more aggressive optimizations. + #[must_use] pub fn get_unnamed_address(&self) -> UnnamedAddr { - unsafe { core::LLVMGetUnnamedAddress(self.0) } + unsafe { UnnamedAddr::from(core::LLVMGetUnnamedAddress(self.0)) } } /// Set the unnamed address of a global value. /// - /// @see llvm::GlobalValue::setUnnamedAddr() + /// ## Details + /// + /// Sets the unnamed address attribute for a global value. + /// + /// This function wraps the `LLVMSetUnnamedAddress` function from the LLVM core library. It configures the + /// unnamed address attribute for the global value represented by `self`. The `UnnamedAddr` attribute specifies + /// whether the address of the global value is significant, which can influence certain optimizations in LLVM. + /// + /// # Parameters + /// + /// - `unnamed_addr`: An `UnnamedAddr` enum value that specifies the unnamed address attribute for the global value. + /// - `NoUnnamedAddr`: The address of the global value is significant and must be unique. + /// - `LocalUnnamedAddr`: The address is not significant within the module, allowing certain optimizations. + /// - `GlobalUnnamedAddr`: The address is not significant across the entire program, enabling more aggressive optimizations. pub fn set_unnamed_address(&self, unnamed_addr: UnnamedAddr) { unsafe { - core::LLVMSetUnnamedAddress(self.0, unnamed_addr); + core::LLVMSetUnnamedAddress(self.0, unnamed_addr.into()); } } /// Returns the "value type" of a global value. This differs from the formal /// type of a global value, which is always a pointer type. /// - /// @see llvm::GlobalValue::getValueType() + /// ## Details + /// + /// Retrieves the type of the global value. + /// + /// This function wraps the `LLVMGlobalGetValueType` function from the LLVM core library. It returns the + /// `TypeRef` representing the type of the global value associated with `self`. Knowing the type of the global value + /// is essential for understanding what kind of data it holds or operates on, as well as for performing type-specific + /// operations or optimizations. + /// + /// # Returns + /// + /// Returns a `TypeRef` representing the type of the global value. + #[must_use] pub fn get_value_type(&self) -> TypeRef { unsafe { TypeRef::from(core::LLVMGlobalGetValueType(self.0)) } } /// Obtain the preferred alignment of the value. /// - /// @see llvm::AllocaInst::getAlignment() - /// @see llvm::LoadInst::getAlignment() - /// @see llvm::StoreInst::getAlignment() - /// @see llvm::AtomicRMWInst::setAlignment() - /// @see llvm::AtomicCmpXchgInst::setAlignment() - /// @see llvm::GlobalValue::getAlignment() + /// ## Details + /// + /// Retrieves the alignment of a global value in bytes. + /// + /// This function wraps the `LLVMGetAlignment` function from the LLVM core library. It returns the alignment + /// requirement of the global value represented by `self`, in terms of the number of bytes. Knowing the alignment + /// can be useful for understanding how the global value is laid out in memory and ensuring that it meets the + /// requirements of the target architecture. + /// + /// # Returns + /// + /// Returns a `u32` representing the alignment of the global value in bytes. + #[must_use] pub fn get_alignment(&self) -> u32 { unsafe { core::LLVMGetAlignment(self.0) as u32 } } /// Set the preferred alignment of the value. /// - /// @see llvm::AllocaInst::setAlignment() - /// @see llvm::LoadInst::setAlignment() - /// @see llvm::StoreInst::setAlignment() - /// @see llvm::AtomicRMWInst::setAlignment() - /// @see llvm::AtomicCmpXchgInst::setAlignment() - /// @see llvm::GlobalValue::setAlignment() + /// ## Details + /// + /// Sets the alignment for a global value in bytes. + /// + /// This function wraps the `LLVMSetAlignment` function from the LLVM core library. It specifies the alignment + /// requirement for the global value represented by `self`, in terms of the number of bytes. Proper alignment can be + /// important for performance, particularly in low-level systems programming, where misaligned accesses can cause + /// performance penalties or even hardware exceptions. + /// + /// # Parameters + /// + /// - `bytes`: A `u32` value representing the desired alignment in bytes. This value must be a power of two. pub fn set_alignment(&self, bytes: u32) { unsafe { - core::LLVMSetAlignment(self.0, bytes as c_uint); + core::LLVMSetAlignment(self.0, *CUint::from(bytes)); } } /// Sets a metadata attachment, erasing the existing metadata attachment if /// it already exists for the given kind. /// - /// @see llvm::GlobalObject::setMetadata() - pub fn global_set_metadata(&self, kind: u32, md: LLVMMetadataRef) { + /// ## Details + /// + /// Sets metadata of a specific kind for a global value. + /// + /// This function wraps the `LLVMGlobalSetMetadata` function from the LLVM core library. It attaches metadata of the + /// specified kind to the global value represented by `self`. If metadata of this kind already exists, it will be replaced + /// with the new metadata provided. Metadata in LLVM is used to attach additional information to global values, such as + /// functions or variables, which can be useful for debugging, optimization, or other purposes. + /// + /// # Parameters + /// + /// - `kind`: A `u32` representing the kind of metadata to be set. The kind ID specifies the category or type of the metadata. + /// - `md`: A `MetadataRef` representing the metadata to be attached to the global value. + pub fn global_set_metadata(&self, kind: u32, md: &MetadataRef) { unsafe { - core::LLVMGlobalSetMetadata(self.0, kind, md); + core::LLVMGlobalSetMetadata(self.0, kind, md.get_ref()); } } /// Erases a metadata attachment of the given kind if it exists. /// - /// @see llvm::GlobalObject::eraseMetadata() + /// ## Details + /// + /// Erases metadata of a specific kind from a global value. + /// + /// This function wraps the `LLVMGlobalEraseMetadata` function from the LLVM core library. It removes the metadata + /// entry of the specified kind associated with the global value represented by `self`. If the global value has multiple + /// metadata entries, only the entry matching the specified kind will be erased, leaving other metadata intact. + /// + /// # Parameters + /// + /// - `kind`: A `u32` representing the kind of metadata to be erased. The kind ID specifies the category or type of the metadata. pub fn global_erase_metadata(&self, kind: u32) { unsafe { - core::LLVMGlobalEraseMetadata(self.0, kind); + core::LLVMGlobalEraseMetadata(self.0, *CUint::from(kind)); } } /// Removes all metadata attachments from this value. /// - /// @see llvm::GlobalObject::clearMetadata() + /// ## Details + /// + /// Clears all metadata attached to a global value. + /// + /// This function wraps the `LLVMGlobalClearMetadata` function from the LLVM core library. It removes all metadata + /// entries associated with the global value represented by `self`. This operation effectively detaches any metadata + /// from the global value, which might be useful in scenarios where the metadata is no longer needed or should be reset. pub fn global_clear_metadata(&self) { unsafe { core::LLVMGlobalClearMetadata(self.0); @@ -177,15 +391,29 @@ impl ValueRef { /// being unavailable. Since there are no cases in which it can be called in /// safe code. For raw access, if there is such a need, must be called /// `LLVMDisposeValueMetadataEntries` directly. - pub fn dispose_value_metadata_entries(_entries: Vec) { + pub fn dispose_value_metadata_entries(_entries: &[ValueMetadataEntry]) { unreachable!("LLVMDisposeValueMetadataEntries is unsafe adn restricted to operated to operate directly for safe code"); } - /// Retrieves an array of metadata entries representing the metadata attached to - /// this value. The caller is responsible for freeing this array by calling - /// `LLVMDisposeValueMetadataEntries`. + /// Retrieves an array of metadata entries representing the metadata attached to this value. /// - /// @see llvm::GlobalObject::getAllMetadata() + /// ## Details + /// + /// Copies all metadata attached to a global value and returns it as a vector of `ValueMetadataEntry`. + /// + /// This function wraps the `LLVMGlobalCopyAllMetadata` function from the LLVM core library. It retrieves all metadata + /// entries associated with the global value represented by `self` and returns them as a vector of `ValueMetadataEntry`. + /// Metadata in LLVM is used to attach additional information to various constructs, such as functions or global variables, + /// which can be useful for debugging, optimization, or other purposes. + /// + /// After copying the metadata entries, the function ensures that any allocated memory for the metadata entries is correctly + /// freed by calling ``LLVMDisposeValueMetadataEntries``. + /// + /// # Returns + /// + /// Returns a `Vec` containing all metadata entries attached to the global value. If no metadata is + /// attached, an empty vector is returned. + #[must_use] pub fn global_copy_all_metadata(&self) -> Vec { let mut num_entries: usize = 0; let entries_ptr = unsafe { core::LLVMGlobalCopyAllMetadata(self.0, &mut num_entries) }; @@ -200,26 +428,97 @@ impl ValueRef { .map(|&entry| ValueMetadataEntry::from(entry)) .collect::>(); - // Free the memory allocated by `LLVMGlobalCopyAllMetadata` + // Free allocated memory unsafe { core::LLVMDisposeValueMetadataEntries(entries_ptr); } entries } +} - /// Returns the kind of a value metadata entry at a specific index. - pub fn get_kind(&self, index: u32) -> u32 { - unsafe { core::LLVMValueMetadataEntriesGetKind(self.0, index as c_uint) as u32 } - } +/// Returns the kind of a value metadata entry at a specific index. +/// +/// ## Details +/// +/// Retrieves the metadata kind ID for a specific entry in a list of value metadata entries. +/// +/// This function wraps the `LLVMValueMetadataEntriesGetKind` function from the LLVM core library. It retrieves +/// the kind ID of the metadata entry at the specified index within the provided vector of `ValueMetadataEntry`. +/// Metadata kinds in LLVM are used to categorize the type of metadata, allowing different kinds of information +/// to be attached to values. +/// +/// # Parameters +/// +/// - `value_metadata_entries`: A vector of `ValueMetadataEntry` from which the metadata kind ID will be retrieved. +/// - `index`: The index of the metadata entry within the vector for which the kind ID is requested. +/// +/// # Returns +/// +/// Returns a `u32` representing the metadata kind ID for the specified entry. +/// +/// # Panics +/// +/// The function may panic if the provided index is out of bounds for the vector, depending on how the underlying +/// LLVM function handles invalid indices. +#[must_use] +pub fn value_metadata_entries_get_kind( + value_metadata_entries: &[ValueMetadataEntry], + index: u32, +) -> u32 { + let mut entries = value_metadata_entries + .iter() + .map(|v| v.0) + .collect::>(); + let entries_ptr = if entries.is_empty() { + std::ptr::null_mut() + } else { + entries.as_mut_ptr() + }; + unsafe { core::LLVMValueMetadataEntriesGetKind(entries_ptr, *CUint::from(index)) } +} - /// Returns the underlying metadata node of a value metadata entry at a specific index. - pub fn get_metadata(&self, index: u32) -> MetadataRef { - unsafe { - MetadataRef::from(core::LLVMValueMetadataEntriesGetMetadata( - self.0, - *CUint::from(index), - )) - } +/// Returns the underlying metadata node of a value metadata entry at a specific index. +/// +/// ## Details +/// +/// Retrieves the metadata reference for a specific entry in a list of value metadata entries. +/// +/// This function wraps the `LLVMValueMetadataEntriesGetMetadata` function from the LLVM core library. It retrieves +/// the `MetadataRef` associated with the metadata entry at the specified index within the provided vector of `ValueMetadataEntry`. +/// This allows you to access the metadata attached to a global value or other LLVM constructs. +/// +/// # Parameters +/// +/// - `value_metadata_entries`: A vector of `ValueMetadataEntry` from which the metadata reference will be retrieved. +/// - `index`: The index of the metadata entry within the vector for which the metadata reference is requested. +/// +/// # Returns +/// +/// Returns a `MetadataRef` representing the metadata associated with the specified entry. +/// +/// # Panics +/// +/// The function may panic if the provided index is out of bounds for the vector, depending on how the underlying +/// LLVM function handles invalid indices. +#[must_use] +pub fn value_metadata_entries_get_metadata( + value_metadata_entries: &[ValueMetadataEntry], + index: u32, +) -> MetadataRef { + let mut entries = value_metadata_entries + .iter() + .map(|v| v.0) + .collect::>(); + let entries_ptr = if entries.is_empty() { + std::ptr::null_mut() + } else { + entries.as_mut_ptr() + }; + unsafe { + MetadataRef::from(core::LLVMValueMetadataEntriesGetMetadata( + entries_ptr, + *CUint::from(index), + )) } } diff --git a/src/core/values/constants/mod.rs b/src/core/values/constants/mod.rs index 0877f3b..98b21a2 100644 --- a/src/core/values/constants/mod.rs +++ b/src/core/values/constants/mod.rs @@ -3,7 +3,7 @@ pub mod composite; pub mod expressions; -mod global_values; +pub mod global_values; pub mod scalar; use super::ValueRef;