1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
//! Functions in this section work on all `ValueRef` instances,
//! regardless of their sub-type. They correspond to functions available
//! on `C LLVM Value`.

use super::{ValueKind, ValueRef};
use crate::core::types::TypeRef;
use crate::{CStr, CString, SizeT};
use llvm_sys::core;

impl ValueRef {
    /// Obtain the type of the value.
    ///
    /// # Details
    ///
    /// Retrieves the LLVM type of the value.
    ///
    /// This function wraps the `LLVMTypeOf` function from the LLVM core library. It returns the `TypeRef` representing
    /// the LLVM type of the value represented by `self`. This is useful for inspecting the type information of values
    /// within LLVM IR, such as determining whether a value is an integer, floating-point, pointer, or another type.
    ///
    /// # Returns
    ///
    /// Returns a `TypeRef` that represents the LLVM type of the value.
    #[must_use]
    pub fn type_of(&self) -> TypeRef {
        unsafe { TypeRef::from(core::LLVMTypeOf(self.0)) }
    }

    /// Returns the kind of the given LLVM value (Obtain the enumerated type of the Value instance.).
    ///
    /// # Details
    ///
    /// Retrieves the kind of value represented by this LLVM value.
    ///
    /// This function wraps the `LLVMGetValueKind` function from the LLVM core library. It returns a `ValueKind`
    /// enumeration that identifies the specific kind of the value, such as whether it is an instruction, a constant,
    /// a global variable, a function, etc. This is useful for understanding what kind of entity a value represents within
    /// the LLVM IR.
    ///
    /// # Returns
    ///
    /// Returns a `ValueKind` enumeration that represents the kind of the value.
    #[must_use]
    pub fn get_value_kind(&self) -> ValueKind {
        unsafe { ValueKind::from(core::LLVMGetValueKind(self.0)) }
    }

    /// Obtain the string name of a value.
    ///
    /// # Details
    ///
    /// Retrieves the name of the LLVM value, if it has one.
    ///
    /// This function wraps the `LLVMGetValueName2` function from the LLVM core library. It returns the name of the
    /// value represented by `self` as a `String`, if the value has a name. In LLVM IR, named values typically include
    /// functions, global variables, and named instructions. If the value does not have a name, the function returns `None`.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the name of the value if it has one.
    /// - `None` if the value does not have a name.
    #[must_use]
    pub fn get_value_name(&self) -> Option<String> {
        unsafe {
            let mut length = SizeT::from(0);
            let c_str = core::LLVMGetValueName2(self.0, &mut *length);
            if c_str.is_null() {
                return None;
            }
            Some(CStr::new(c_str).to_string())
        }
    }

    /// Set the string name of a value.
    ///
    /// # Details
    ///
    /// Sets the name of the LLVM value.
    ///
    /// This function wraps the `LLVMSetValueName2` function from the LLVM core library. It assigns a new name
    /// to the value represented by `self`. Naming a value in LLVM IR is useful for debugging, readability, and
    /// when generating human-readable IR. Named values typically include functions, global variables, and named
    /// instructions.
    ///
    /// # Parameters
    ///
    /// - `name`: A string slice (`&str`) representing the new name to assign to the value.
    ///
    /// # Example
    ///
    /// ```rust
    /// let my_value: ValueRef; // Assume this is an LLVM value.
    /// my_value.set_value_name("my_value_name");
    /// ```
    ///
    /// After calling this function, the value will be named "`my_value_name`" in the LLVM IR.
    pub fn set_value_name(&self, name: &str) {
        let c_string = CString::from(name);
        unsafe {
            core::LLVMSetValueName2(self.0, c_string.as_ptr(), *SizeT::from(name.len()));
        }
    }

    /// Dump a representation of a value to stderr.
    ///
    /// # Details
    ///
    /// Dumps a textual representation of the LLVM value to standard output.
    ///
    /// This function wraps the `LLVMDumpValue` function from the LLVM core library. It prints a human-readable
    /// representation of the value represented by `self` to standard output. This is useful for debugging or
    /// inspecting the contents of a value during development.
    pub fn dump_value(&self) {
        unsafe { core::LLVMDumpValue(self.0) }
    }

    /// Return a string representation of the value. Use
    /// `dispose_message` to free the string.
    ///
    /// # Details
    ///
    /// Converts the LLVM value to a human-readable string representation.
    ///
    /// This function wraps the `LLVMPrintValueToString` function from the LLVM core library. It returns a
    /// string containing a human-readable representation of the value represented by `self`. This is useful
    /// for debugging or inspecting the contents of a value programmatically.
    ///
    /// The function returns `None` if the conversion fails or if the value cannot be represented as a string.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the string representation of the value if successful.
    /// - `None` if the conversion fails or the value cannot be represented as a string.
    #[must_use]
    pub fn print_value_to_string(&self) -> Option<String> {
        unsafe {
            let c_str = core::LLVMPrintValueToString(self.0);
            if c_str.is_null() {
                return None;
            }
            let result = CStr::new(c_str).to_string();
            crate::core::dispose_message(c_str);
            Some(result)
        }
    }

    /// Replace all uses of a value with another one.
    ///
    /// # Details
    ///
    /// Replaces all uses of this value with another value in the LLVM IR.
    ///
    /// This function wraps the `LLVMReplaceAllUsesWith` function from the LLVM core library. It replaces
    /// every use of the value represented by `self` with the value represented by `new_val`. This is useful
    /// for modifying LLVM IR when you need to substitute one value with another throughout the IR.
    ///
    /// # Parameters
    ///
    /// - `new_val`: A reference to the value that will replace all uses of `ValueRef`.
    pub fn replace_all_uses_with(&self, new_val: &Self) {
        unsafe { core::LLVMReplaceAllUsesWith(self.0, new_val.0) }
    }

    /// Determines whether the specified value instance is constant.
    ///
    /// # Details
    ///
    /// Checks if the value is a constant in LLVM IR.
    ///
    /// This function wraps the `LLVMIsConstant` function from the LLVM core library. It determines whether
    /// the value represented by `self` is a constant. In LLVM IR, constants are values that are known at compile time,
    /// such as integer literals, floating-point literals, or constant expressions.
    ///
    /// # Returns
    ///
    /// Returns `true` if the value is a constant, otherwise returns `false`.
    #[must_use]
    pub fn is_constant(&self) -> bool {
        unsafe { core::LLVMIsConstant(self.0) != 0 }
    }

    /// Determine whether a value instance is undefined.
    ///
    /// # Details
    ///
    /// Checks if the value is an 'undefined' value in LLVM IR.
    ///
    /// This function wraps the `LLVMIsUndef` function from the LLVM core library. It determines whether
    /// the value represented by `self` is an 'undefined' value. In LLVM IR, an undefined value is a placeholder
    /// that can take any value of the specified type during program execution, often used in optimization phases.
    ///
    /// # Returns
    ///
    /// Returns `true` if the value is an undefined value, otherwise returns `false`.
    #[must_use]
    pub fn is_undef(&self) -> bool {
        unsafe { core::LLVMIsUndef(self.0) != 0 }
    }

    /// Determine whether a value instance is poisonous.
    ///
    /// # Details
    ///
    /// Checks if the value is a 'poison' value in LLVM IR.
    ///
    /// This function wraps the `LLVMIsPoison` function from the LLVM core library. It determines whether
    /// the value represented by `self` is a 'poison' value. In LLVM IR, a poison value results from an operation
    /// with undefined behavior and can propagate through further operations, potentially leading to incorrect results.
    ///
    /// # Returns
    ///
    /// Returns `true` if the value is a poison value, otherwise returns `false`.
    #[must_use]
    pub fn is_poison(&self) -> bool {
        unsafe { core::LLVMIsPoison(self.0) != 0 }
    }

    /// Determines whether the specified value instance is an `AMD` node.
    ///
    /// # Details
    ///
    /// Checks if the value is an AMD node in LLVM IR and returns the corresponding value.
    ///
    /// This function wraps the `LLVMIsAMDNode` function from the LLVM core library. It determines whether
    /// the value represented by `self` is an AMD node and returns the corresponding value if it is. AMD nodes
    /// are specific to AMD's extensions in LLVM, and this function is used to identify and work with those nodes.
    ///
    /// # Returns
    ///
    /// Returns an instance of `Self` that represents the value if it is an AMD node.
    #[must_use]
    pub fn is_amd_node(&self) -> Self {
        unsafe { Self(core::LLVMIsAMDNode(self.0)) }
    }

    /// Determines whether the specified value instance is a value as metadata.
    ///
    /// # Details
    ///
    /// Checks if the value can be treated as metadata in LLVM IR and returns the corresponding value.
    ///
    /// This function wraps the `LLVMIsAValueAsMetadata` function from the LLVM core library. It determines whether
    /// the value represented by `self` can be treated as metadata and returns the corresponding value if it can. In LLVM IR,
    /// some values can also be used as metadata, which is often used for attaching additional information to instructions
    /// or other IR elements.
    ///
    /// # Returns
    ///
    /// Returns an instance of `Self` that represents the value if it can be treated as metadata.
    #[must_use]
    pub fn is_value_as_metadata(&self) -> Self {
        unsafe { Self(core::LLVMIsAValueAsMetadata(self.0)) }
    }

    /// Determines whether the specified value instance is an `AMD` string.
    ///
    /// # Details
    ///
    /// Checks if the value is an AMD string in LLVM IR and returns the corresponding value.
    ///
    /// This function wraps the `LLVMIsAMDString` function from the LLVM core library. It determines whether
    /// the value represented by `self` is an AMD string and returns the corresponding value if it is. AMD strings
    /// are specific to AMD's extensions in LLVM, and this function is used to identify and work with those strings.
    ///
    /// # Returns
    ///
    /// Returns an instance of `Self` that represents the value if it is an AMD string.
    #[must_use]
    pub fn is_amd_string(&self) -> Self {
        unsafe { Self(core::LLVMIsAMDString(self.0)) }
    }
}