Skip to main content

inkwell/values/
metadata_value.rs

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