inkwell/values/
metadata_value.rs

1use llvm_sys::core::{
2    LLVMGetMDNodeNumOperands, LLVMGetMDNodeOperands, LLVMGetMDString, LLVMIsAMDNode, LLVMIsAMDString,
3};
4use llvm_sys::prelude::LLVMValueRef;
5
6#[llvm_versions(7..)]
7use llvm_sys::core::LLVMValueAsMetadata;
8#[llvm_versions(7..)]
9use llvm_sys::prelude::LLVMMetadataRef;
10
11use crate::values::traits::AsValueRef;
12use crate::values::{BasicMetadataValueEnum, Value};
13
14use super::AnyValue;
15
16use std::ffi::CStr;
17use std::fmt::{self, Display};
18
19/// Value returned by [`Context::get_kind_id()`](crate::context::Context::get_kind_id)
20/// for the first input string that isn't known.
21///
22/// Each LLVM version has a different set of pre-defined metadata kinds.
23pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = if cfg!(feature = "llvm4-0") {
24    22
25} else if cfg!(feature = "llvm5-0") {
26    23
27} else if cfg!(any(feature = "llvm6-0", feature = "llvm7-0")) {
28    25
29} else if cfg!(feature = "llvm8-0") {
30    26
31} else if cfg!(feature = "llvm9-0") {
32    28
33} else if cfg!(any(feature = "llvm10-0", feature = "llvm11-0")) {
34    30
35} else if cfg!(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0",)) {
36    31
37} else if cfg!(feature = "llvm15-0") {
38    36
39} else if cfg!(any(feature = "llvm16-0", feature = "llvm17-0")) {
40    39
41} else if cfg!(feature = "llvm18-0") {
42    40
43} else {
44    panic!("Unhandled LLVM version")
45};
46
47#[derive(PartialEq, Eq, Clone, Copy, Hash)]
48pub struct MetadataValue<'ctx> {
49    metadata_value: Value<'ctx>,
50}
51
52impl<'ctx> MetadataValue<'ctx> {
53    /// Get a value from an [LLVMValueRef].
54    ///
55    /// # Safety
56    ///
57    /// The ref must be valid and of type metadata.
58    pub unsafe fn new(value: LLVMValueRef) -> Self {
59        assert!(!value.is_null());
60        assert!(!LLVMIsAMDNode(value).is_null() || !LLVMIsAMDString(value).is_null());
61
62        MetadataValue {
63            metadata_value: Value::new(value),
64        }
65    }
66
67    #[llvm_versions(7..)]
68    pub(crate) fn as_metadata_ref(self) -> LLVMMetadataRef {
69        unsafe { LLVMValueAsMetadata(self.as_value_ref()) }
70    }
71
72    /// Get name of the `MetadataValue`.
73    pub fn get_name(&self) -> &CStr {
74        self.metadata_value.get_name()
75    }
76
77    // SubTypes: This can probably go away with subtypes
78    pub fn is_node(self) -> bool {
79        unsafe { LLVMIsAMDNode(self.as_value_ref()) == self.as_value_ref() }
80    }
81
82    // SubTypes: This can probably go away with subtypes
83    pub fn is_string(self) -> bool {
84        unsafe { LLVMIsAMDString(self.as_value_ref()) == self.as_value_ref() }
85    }
86
87    pub fn get_string_value(&self) -> Option<&CStr> {
88        if self.is_node() {
89            return None;
90        }
91
92        let mut len = 0;
93        let c_str = unsafe { CStr::from_ptr(LLVMGetMDString(self.as_value_ref(), &mut len)) };
94
95        Some(c_str)
96    }
97
98    // SubTypes: Node only one day
99    pub fn get_node_size(self) -> u32 {
100        if self.is_string() {
101            return 0;
102        }
103
104        unsafe { LLVMGetMDNodeNumOperands(self.as_value_ref()) }
105    }
106
107    // SubTypes: Node only one day
108    // REVIEW: BasicMetadataValueEnum only if you can put metadata in metadata...
109    pub fn get_node_values(self) -> Vec<BasicMetadataValueEnum<'ctx>> {
110        if self.is_string() {
111            return Vec::new();
112        }
113
114        let count = self.get_node_size() as usize;
115        let mut vec: Vec<LLVMValueRef> = Vec::with_capacity(count);
116        let ptr = vec.as_mut_ptr();
117
118        unsafe {
119            LLVMGetMDNodeOperands(self.as_value_ref(), ptr);
120
121            vec.set_len(count)
122        };
123
124        vec.iter()
125            .map(|val| unsafe { BasicMetadataValueEnum::new(*val) })
126            .collect()
127    }
128
129    pub fn print_to_stderr(self) {
130        self.metadata_value.print_to_stderr()
131    }
132
133    pub fn replace_all_uses_with(self, other: &MetadataValue<'ctx>) {
134        self.metadata_value.replace_all_uses_with(other.as_value_ref())
135    }
136}
137
138unsafe impl AsValueRef for MetadataValue<'_> {
139    fn as_value_ref(&self) -> LLVMValueRef {
140        self.metadata_value.value
141    }
142}
143
144impl Display for MetadataValue<'_> {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(f, "{}", self.print_to_string())
147    }
148}
149
150impl fmt::Debug for MetadataValue<'_> {
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        let mut d = f.debug_struct("MetadataValue");
153        d.field("address", &self.as_value_ref());
154
155        if self.is_string() {
156            d.field("value", &self.get_string_value().unwrap());
157        } else {
158            d.field("values", &self.get_node_values());
159        }
160
161        d.field("repr", &self.print_to_string());
162
163        d.finish()
164    }
165}