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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
//! Functions in this group model `ValueRef` instances that correspond
//! to constants referring to scalar types.

use super::ValueRef;
use crate::core::types::TypeRef;
use crate::{CDouble, CInt, CString, CUint, GetRef};
use llvm_sys::core;

impl ValueRef {
    /// Obtain a constant value for an integer type.
    /// The returned value corresponds to a `llvm ConstantInt`.
    ///
    /// # Details
    ///
    /// Creates a constant integer value of a specified type.
    ///
    /// This function wraps the `LLVMConstInt` function from the LLVM core library. It generates a constant integer
    /// value of the type specified by `ty`, using the provided `n` as the value. The `sign_extend` parameter determines
    /// whether the value should be sign-extended to the specified type if the type is larger than the original value.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the integer type (`TypeRef`) for the constant value. This specifies the bit width and signedness of the integer.
    /// - `n`: The integer value to be used for the constant. It will be interpreted according to the bit width and signedness of the target type.
    /// - `sign_extend`: A boolean value indicating whether the constant should be sign-extended to the target type. If `true`, the value will be sign-extended; if `false`, it will be zero-extended.
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant integer value determined at compile time.
    #[must_use]
    pub fn const_int(ty: &TypeRef, n: u64, sign_extend: bool) -> Self {
        unsafe {
            Self(core::LLVMConstInt(
                ty.get_ref(),
                n,
                *CInt::from(sign_extend),
            ))
        }
    }

    /// Obtain a constant value for an integer of arbitrary precision.
    ///
    /// # Details
    ///
    /// Creates a constant integer value of arbitrary precision.
    ///
    /// This function wraps the `LLVMConstIntOfArbitraryPrecision` function from the LLVM core library. It generates a constant
    /// integer value of the specified type (`ty`) using an array of 64-bit words (`words`). This allows for the creation of
    /// integers that exceed the typical bit width limitations by providing multiple 64-bit words to represent the value.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the integer type (`TypeRef`) for the constant value. This type specifies the bit width and signedness of the integer.
    /// - `words`: A slice of 64-bit words (`u64`) that represents the value of the constant integer. Each word in the array contributes to the overall bit representation of the integer, allowing for arbitrary precision.
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant integer value with arbitrary precision, as determined at compile time.
    #[must_use]
    pub fn const_int_of_arbitrary_precision(ty: &TypeRef, words: &[u64]) -> Self {
        unsafe {
            Self(core::LLVMConstIntOfArbitraryPrecision(
                ty.get_ref(),
                *CUint::from(words.len()),
                words.as_ptr(),
            ))
        }
    }

    /// Obtain a constant value for an integer parsed from a string.
    ///
    /// A similar API, `const_int_of_string_and_size` is also available. If the
    /// string's length is available, it is preferred to call that function
    /// instead.
    ///
    /// # Details
    ///
    /// Creates a constant integer value by parsing a string representation of the integer.
    ///
    /// This function wraps the `LLVMConstIntOfString` function from the LLVM core library. It generates a constant
    /// integer value of the specified type (`ty`) by parsing the provided string (`text`) according to the specified
    /// radix (`radix`). This function is useful when you need to create constant integers from string literals in various bases
    /// (e.g., binary, octal, decimal, hexadecimal).
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the integer type (`TypeRef`) for the constant value. This type specifies the bit width and signedness of the integer.
    /// - `text`: A string slice that represents the integer value to be parsed. The string should be a valid representation of an integer in the specified radix.
    /// - `radix`: The radix (or base) used to interpret the string. Common values include 2 (binary), 8 (octal), 10 (decimal), and 16 (hexadecimal).
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant integer value parsed from the string at compile time.
    #[must_use]
    pub fn const_int_of_string(ty: &TypeRef, text: &str, radix: u8) -> Self {
        let c_text = CString::from(text);
        unsafe {
            Self(core::LLVMConstIntOfString(
                ty.get_ref(),
                c_text.as_ptr(),
                radix,
            ))
        }
    }

    /// Obtain a constant value for an integer parsed from a string with
    /// specified length.
    ///
    /// # Details
    ///
    /// Creates a constant integer value by parsing a string representation of the integer, with a specified string length.
    ///
    /// This function wraps the `LLVMConstIntOfStringAndSize` function from the LLVM core library. It generates a constant
    /// integer value of the specified type (`ty`) by parsing the provided string (`text`) according to the specified
    /// radix (`radix`). The length of the string is explicitly provided, which can be more efficient when the string length
    /// is known or can be easily determined, as it avoids the need for additional computation or checks.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the integer type (`TypeRef`) for the constant value. This type specifies the bit width and signedness of the integer.
    /// - `text`: A string slice that represents the integer value to be parsed. The string should be a valid representation of an integer in the specified radix.
    /// - `radix`: The radix (or base) used to interpret the string. Common values include 2 (binary), 8 (octal), 10 (decimal), and 16 (hexadecimal).
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant integer value parsed from the string at compile time.
    ///
    /// # Efficiency
    ///
    /// This function is recommended when the length of the string is known, as it may offer better performance
    /// compared to `const_int_of_string` by avoiding the overhead of calculating the string length within the function.
    #[must_use]
    pub fn const_int_of_string_and_size(ty: &TypeRef, text: &str, radix: u8) -> Self {
        let c_text = CString::from(text);
        unsafe {
            Self(core::LLVMConstIntOfStringAndSize(
                ty.get_ref(),
                c_text.as_ptr(),
                *CUint::from(text.len()),
                radix,
            ))
        }
    }

    /// Obtain a constant value referring to a double floating point value.
    ///
    /// # Details
    ///
    /// Creates a constant floating-point value of a specified type.
    ///
    /// This function wraps the `LLVMConstReal` function from the LLVM core library. It generates a constant
    /// floating-point value of the type specified by `ty`, using the provided floating-point number `n`. This is
    /// typically used to create floating-point constants within LLVM's Intermediate Representation (IR) at compile time.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the floating-point type (`TypeRef`) for the constant value. This type specifies the bit width of the floating-point value (e.g., `f32`, `f64`).
    /// - `n`: The floating-point value to be used for the constant. It will be interpreted according to the bit width of the target floating-point type.
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant floating-point value determined at compile time.
    #[must_use]
    pub fn const_real(ty: &TypeRef, n: f64) -> Self {
        unsafe { Self(core::LLVMConstReal(ty.get_ref(), *CDouble::from(n))) }
    }

    /// Obtain a constant for a floating point value parsed from a string.
    ///
    /// A similar API, `const_real_of_string_and_size` is also available. It
    /// should be used if the input string's length is known.
    ///
    /// # Details
    ///
    /// Creates a constant floating-point value by parsing a string representation of the number.
    ///
    /// This function wraps the `LLVMConstRealOfString` function from the LLVM core library. It generates a constant
    /// floating-point value of the specified type (`ty`) by parsing the provided string (`text`). This is useful when
    /// creating floating-point constants from string literals, especially when the value is specified in textual form
    /// rather than directly as a floating-point number.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the floating-point type (`TypeRef`) for the constant value. This type specifies the bit width of the floating-point value (e.g., `f32`, `f64`).
    /// - `text`: A string slice that represents the floating-point value to be parsed. The string should be a valid representation of a floating-point number in the expected format.
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant floating-point value parsed from the string at compile time.
    #[must_use]
    pub fn const_real_of_string(ty: &TypeRef, text: &str) -> Self {
        let c_text = CString::from(text);
        unsafe { Self(core::LLVMConstRealOfString(ty.get_ref(), c_text.as_ptr())) }
    }

    /// Obtain a constant for a floating point value parsed from a string with specified length.
    ///
    /// # Details
    ///
    /// Creates a constant floating-point value by parsing a string representation of the number, with a specified string length.
    ///
    /// This function wraps the `LLVMConstRealOfStringAndSize` function from the LLVM core library. It generates a constant
    /// floating-point value of the specified type (`ty`) by parsing the provided string (`text`) according to its length.
    /// This function is useful when the length of the input string is known, as it may provide better performance by
    /// avoiding the need to compute the string length internally.
    ///
    /// # Parameters
    ///
    /// - `ty`: A reference to the floating-point type (`TypeRef`) for the constant value. This type specifies the bit width of the floating-point value (e.g., `f32`, `f64`).
    /// - `text`: A string slice that represents the floating-point value to be parsed. The string should be a valid representation of a floating-point number in the expected format.
    ///
    /// # Returns
    ///
    /// Returns an instance of `ValueRef`, which encapsulates the constant floating-point value parsed from the string at compile time.
    ///
    /// # Efficiency
    ///
    /// This function is recommended when the length of the string is known, as it may offer better performance
    /// compared to `const_real_of_string` by avoiding the overhead of calculating the string length within the function.
    #[must_use]
    pub fn const_real_of_string_and_size(ty: &TypeRef, text: &str) -> Self {
        let c_text = CString::from(text);
        unsafe {
            Self(core::LLVMConstRealOfStringAndSize(
                ty.get_ref(),
                c_text.as_ptr(),
                *CUint::from(text.len()),
            ))
        }
    }

    /// Obtain the zero extended value for an integer constant value.
    ///
    /// # Details
    ///
    /// Retrieves the zero-extended value of a constant integer as a `u64`.
    ///
    /// This function wraps the `LLVMConstIntGetZExtValue` function from the LLVM core library. It returns the value
    /// of the constant integer represented by `self`, zero-extending it to 64 bits if necessary. This is useful when you need
    /// to extract the numeric value of a constant integer in a form that can be used in regular Rust code.
    ///
    /// # Returns
    ///
    /// Returns a `u64` that represents the zero-extended value of the constant integer.
    #[must_use]
    pub fn const_int_get_zext_value(&self) -> u64 {
        unsafe { core::LLVMConstIntGetZExtValue(self.0) }
    }

    /// Obtain the sign extended value for an integer constant value.
    ///
    /// # Details
    ///
    /// Retrieves the sign-extended value of a constant integer as an `i64`.
    ///
    /// This function wraps the `LLVMConstIntGetSExtValue` function from the LLVM core library. It returns the value
    /// of the constant integer represented by `self`, sign-extending it to 64 bits if necessary. This is useful when you need
    /// to extract the numeric value of a constant integer in a signed form that can be used in regular Rust code.
    ///
    /// # Returns
    ///
    /// Returns an `i64` that represents the sign-extended value of the constant integer.
    #[must_use]
    pub fn const_int_get_sext_value(&self) -> i64 {
        unsafe { core::LLVMConstIntGetSExtValue(self.0) }
    }

    /// Obtain the double value for a floating point constant value.
    /// `losesInfo` indicates if some precision was lost in the conversion.
    ///
    /// # Details
    ///
    /// Retrieves the double-precision floating-point value from a constant floating-point value.
    ///
    /// This function wraps the `LLVMConstRealGetDouble` function from the LLVM core library. It extracts the value
    /// of the constant floating-point represented by `self` as an `f64`. The function also indicates if any precision
    /// was lost during the conversion by setting the `losesInfo` flag.
    ///
    /// # Returns
    ///
    /// Returns a tuple containing:
    /// - An `f64` representing the double-precision floating-point value.
    /// - A `bool` flag (`losesInfo`) indicating whether some precision was lost in the conversion (`true` if precision was lost, `false` otherwise).
    #[must_use]
    pub fn const_real_get_double(&self) -> (f64, bool) {
        let mut loses_info_c = 0;
        let result = unsafe { core::LLVMConstRealGetDouble(self.0, &mut loses_info_c) };
        (result, loses_info_c != 0)
    }
}