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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
use crate::core::module::InlineAsmDialect;
use crate::core::types::TypeRef;
use crate::{CStr, CUint, GetRef, SizeT};
use llvm_sys::core;
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::LLVMValueKind;
use std::ops::Deref;

pub mod constants;
pub mod general;
pub mod uses;

pub use constants::ConstValueRef;

/// Represents the different kinds of values in LLVM IR.
///
/// The `ValueKind` enum categorizes the various types of values that can exist within LLVM IR. Each variant
/// of this enum corresponds to a specific kind of value or entity in the LLVM IR, such as a function, global variable,
/// instruction, or constant. This enum is useful for identifying the type of a value when working with LLVM IR structures.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ValueKind {
    /// Represents a function argument. Each argument passed to a function is an instance of this kind.
    Argument,
    /// Represents a basic block within a function. Basic blocks are the building blocks of a function's control flow.
    BasicBlock,
    /// Represents a memory use in the `MemorySSA`. This kind tracks the use of memory locations within SSA form.
    MemoryUse,
    /// Represents a memory definition in the `MemorySSA`. This kind tracks the definition of memory locations within SSA form.
    MemoryDef,
    /// Represents a memory PHI node in the `MemorySSA`. This kind handles merging memory states from different control flow paths.
    MemoryPhi,
    /// Represents a function. Functions are the primary callable entities in LLVM IR.
    Function,
    /// Represents a global alias. Global aliases are alternative names for global variables or functions.
    GlobalAlias,
    /// Represents an indirect function. This is a function pointer that can be resolved at runtime to a specific implementation.
    GlobalIFunc,
    /// Represents a global variable. Global variables are variables that are globally accessible across the entire module.
    GlobalVariable,
    /// Represents a block address. This is used to refer to the address of a basic block within a function.
    BlockAddress,
    /// Represents a constant expression. Constant expressions are constant values that are computed at compile time from other constants.
    ConstantExpr,
    /// Represents a constant array. Constant arrays are arrays whose elements are all constant values.
    ConstantArray,
    /// Represents a constant struct. Constant structs are structures whose fields are all constant values.
    ConstantStruct,
    /// Represents a constant vector. Constant vectors are vectors whose elements are all constant values.
    ConstantVector,
    /// Represents an undefined value. Undefined values are placeholders that can take any value of their type during execution.
    Undef,
    /// Represents a constant aggregate with all elements set to zero. This includes arrays, structs, and vectors with all elements set to zero.
    ConstantAggregateZero,
    /// Represents a constant data array. These are arrays of simple data types like integers or floating-point numbers, stored as constants.
    ConstantDataArray,
    /// Represents a constant data vector. These are vectors of simple data types like integers or floating-point numbers, stored as constants.
    ConstantDataVector,
    /// Represents a constant integer. Constant integers are fixed integer values known at compile time.
    ConstantInt,
    /// Represents a constant floating-point value. Constant floating-point values are fixed floating-point numbers known at compile time.
    ConstantFP,
    /// Represents a constant null pointer. This is a pointer that is explicitly set to null.
    ConstantPointerNull,
    /// Represents a constant token with no value. Used in certain intrinsic functions that deal with tokens.
    ConstantTokenNone,
    /// Represents metadata used as a value. Metadata can be used to store extra information for optimizations, debugging, or analysis.
    MetadataAsValue,
    /// Represents inline assembly code. Inline assembly allows embedding low-level assembly code within LLVM IR.
    InlineAsm,
    /// Represents an instruction. Instructions are the individual operations that make up the body of functions.
    Instruction,
    /// Represents a poison value. Poison values result from operations with undefined behavior and can propagate to cause further undefined behavior.
    Poison,
    /// Represents a target-specific constant value that has no direct representation in the source code.
    ConstantTargetNone,
}

impl From<LLVMValueKind> for ValueKind {
    fn from(value: LLVMValueKind) -> Self {
        match value {
            LLVMValueKind::LLVMArgumentValueKind => Self::Argument,
            LLVMValueKind::LLVMBasicBlockValueKind => Self::BasicBlock,
            LLVMValueKind::LLVMMemoryUseValueKind => Self::MemoryUse,
            LLVMValueKind::LLVMMemoryDefValueKind => Self::MemoryDef,
            LLVMValueKind::LLVMMemoryPhiValueKind => Self::MemoryPhi,
            LLVMValueKind::LLVMFunctionValueKind => Self::Function,
            LLVMValueKind::LLVMGlobalAliasValueKind => Self::GlobalAlias,
            LLVMValueKind::LLVMGlobalIFuncValueKind => Self::GlobalIFunc,
            LLVMValueKind::LLVMGlobalVariableValueKind => Self::GlobalVariable,
            LLVMValueKind::LLVMBlockAddressValueKind => Self::BlockAddress,
            LLVMValueKind::LLVMConstantExprValueKind => Self::ConstantExpr,
            LLVMValueKind::LLVMConstantArrayValueKind => Self::ConstantArray,
            LLVMValueKind::LLVMConstantStructValueKind => Self::ConstantStruct,
            LLVMValueKind::LLVMConstantVectorValueKind => Self::ConstantVector,
            LLVMValueKind::LLVMUndefValueValueKind => Self::Undef,
            LLVMValueKind::LLVMConstantAggregateZeroValueKind => Self::ConstantAggregateZero,
            LLVMValueKind::LLVMConstantDataArrayValueKind => Self::ConstantDataArray,
            LLVMValueKind::LLVMConstantDataVectorValueKind => Self::ConstantDataVector,
            LLVMValueKind::LLVMConstantIntValueKind => Self::ConstantInt,
            LLVMValueKind::LLVMConstantFPValueKind => Self::ConstantFP,
            LLVMValueKind::LLVMConstantPointerNullValueKind => Self::ConstantPointerNull,
            LLVMValueKind::LLVMConstantTokenNoneValueKind => Self::ConstantTokenNone,
            LLVMValueKind::LLVMMetadataAsValueValueKind => Self::MetadataAsValue,
            LLVMValueKind::LLVMInlineAsmValueKind => Self::InlineAsm,
            LLVMValueKind::LLVMInstructionValueKind => Self::Instruction,
            LLVMValueKind::LLVMPoisonValueKind => Self::Poison,
            LLVMValueKind::LLVMConstantTargetNoneValueKind => Self::ConstantTargetNone,
        }
    }
}

/// LLVM Value wrapper
#[derive(Debug)]
pub struct ValueRef(LLVMValueRef);

impl Deref for ValueRef {
    type Target = LLVMValueRef;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl GetRef for ValueRef {
    type RawRef = LLVMValueRef;
    fn get_ref(&self) -> Self::RawRef {
        self.0
    }
}

impl From<LLVMValueRef> for ValueRef {
    fn from(value_ref: LLVMValueRef) -> Self {
        Self(value_ref)
    }
}

/// That implementations related to LLVM Modules `MemoryDef`.
impl ValueRef {
    /// Get the template string used for an inline assembly snippet.
    ///
    /// # Details
    ///
    /// Retrieves the assembly code string from the inline assembly block in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmAsmString` function from the LLVM core library. It returns the
    /// assembly code string used by the inline assembly block associated with `self`. This string contains the
    /// actual assembly instructions that will be executed as part of the inline assembly.
    ///
    /// If the assembly string cannot be retrieved, the function returns `None`.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the assembly code string if successful.
    /// - `None` if the assembly string cannot be retrieved.
    #[must_use]
    pub fn get_inline_asm_asm_string(&self) -> Option<String> {
        unsafe {
            let mut length = SizeT::from(0_usize);
            let c_str = core::LLVMGetInlineAsmAsmString(self.0, &mut *length);
            if c_str.is_null() {
                return None;
            }
            Some(CStr::new(c_str).to_string())
        }
    }

    /// Get the raw constraint string for an inline assembly snippet.
    ///
    /// # Details
    ///
    /// Retrieves the constraint string associated with the inline assembly block in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmConstraintString` function from the LLVM core library. It returns the
    /// constraint string used by the inline assembly block associated with `self`. The constraint string specifies the
    /// constraints on the operands used in the inline assembly, such as register classes or memory addressing modes.
    ///
    /// If the constraint string cannot be retrieved, the function returns `None`.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the constraint string if successful.
    /// - `None` if the constraint string cannot be retrieved.
    #[must_use]
    pub fn get_inline_asm_constraint_string(&self) -> Option<String> {
        unsafe {
            let mut length = SizeT::from(0_usize);
            let c_str = core::LLVMGetInlineAsmConstraintString(self.0, &mut *length);
            if c_str.is_null() {
                return None;
            }
            Some(CStr::new(c_str).to_string())
        }
    }

    /// Get the dialect used by the inline asm snippet.
    ///
    /// # Details
    ///
    /// Retrieves the dialect of the inline assembly block in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmDialect` function from the LLVM core library. It returns the
    /// `InlineAsmDialect` representing the dialect used by the inline assembly block associated with `self`.
    /// The dialect determines the syntax and conventions used in the inline assembly, which may vary between
    /// different assemblers (e.g., AT&T vs. Intel syntax).
    ///
    /// # Returns
    ///
    /// Returns an `InlineAsmDialect` that represents the dialect of the inline assembly block.
    #[must_use]
    pub fn get_inline_asm_dialect(&self) -> InlineAsmDialect {
        let inline_asm_dialect = unsafe { core::LLVMGetInlineAsmDialect(self.0) };
        inline_asm_dialect.into()
    }

    /// Get the function type of the inline assembly snippet.
    ///
    /// This is the same type that was passed into `LLVMGetInlineAsm` originally.
    ///
    /// # Returns
    ///
    /// Retrieves the function type of the inline assembly block in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmFunctionType` function from the LLVM core library. It returns the
    /// `TypeRef` representing the function type of the inline assembly block associated with `self`. The function type
    /// defines the signature of the inline assembly, including the types of its arguments and return value.
    ///
    /// # Returns
    ///
    /// Returns a `TypeRef` that represents the function type of the inline assembly block.
    #[must_use]
    pub fn get_inline_asm_function_type(&self) -> TypeRef {
        TypeRef::from(unsafe { core::LLVMGetInlineAsmFunctionType(self.0) })
    }

    /// Get if the inline asm snippet has side effects
    ///
    /// # Details
    ///
    /// Checks whether an inline assembly block has side effects in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmHasSideEffects` function from the LLVM core library. It determines
    /// whether the inline assembly represented by `self` has side effects, meaning that it may alter state or interact
    /// with external systems in ways that are not visible within the LLVM IR. This flag is important for optimizations,
    /// as it indicates that the inline assembly cannot be removed or reordered without potentially affecting program behavior.
    ///
    /// # Returns
    ///
    /// Returns `true` if the inline assembly block has side effects, otherwise returns `false`.
    #[must_use]
    pub fn get_inline_asm_has_side_effects(&self) -> bool {
        unsafe { core::LLVMGetInlineAsmHasSideEffects(self.0) != 0 }
    }

    /// Get if the inline asm snippet needs an aligned stack
    ///
    /// # Details
    ///
    /// Checks whether an inline assembly block requires an aligned stack in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmNeedsAlignedStack` function from the LLVM core library. It determines
    /// whether the inline assembly represented by `self` requires the stack to be aligned. Proper stack alignment
    /// may be necessary for certain instructions or calling conventions, and this flag indicates whether such alignment
    /// is needed.
    ///
    /// # Returns
    ///
    /// Returns `true` if the inline assembly block requires an aligned stack, otherwise returns `false`.
    #[must_use]
    pub fn get_inline_asm_needs_aligned_stack(&self) -> bool {
        unsafe { core::LLVMGetInlineAsmNeedsAlignedStack(self.0) != 0 }
    }

    /// Get if the inline asm snippet may unwind the stack
    ///
    /// # Details
    ///
    /// Checks whether an inline assembly block can unwind in LLVM IR.
    ///
    /// This function wraps the `LLVMGetInlineAsmCanUnwind` function from the LLVM core library. It determines whether
    /// the inline assembly represented by `self` is capable of unwinding, which can affect how exceptions and
    /// other control flows are handled during execution.
    ///
    /// # Returns
    ///
    /// Returns `true` if the inline assembly block can unwind, otherwise returns `false`.
    #[must_use]
    pub fn get_inline_asm_can_unwind(&self) -> bool {
        unsafe { core::LLVMGetInlineAsmCanUnwind(self.0) != 0 }
    }

    /// Return the directory of the debug location for this value, which must be
    /// an LLVM `Instruction`, `GlobalVariable`, or `Function`.
    ///
    /// # Details
    ///
    /// Retrieves the directory from the debug location associated with this value in LLVM IR.
    ///
    /// This function wraps the `LLVMGetDebugLocDirectory` function from the LLVM core library. It returns the
    /// directory of the source code location associated with the debug information for the value represented by `self`.
    /// If the directory cannot be retrieved, the function returns `None`.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the directory associated with the value's debug location if successful.
    /// - `None` if the directory cannot be retrieved.
    #[must_use]
    pub fn get_debug_loc_directory(&self) -> Option<String> {
        unsafe {
            let mut length = CUint::from(0_usize);
            let c_str = core::LLVMGetDebugLocDirectory(self.0, &mut *length);
            if c_str.is_null() {
                return None;
            }
            Some(CStr::new(c_str).to_string())
        }
    }

    /// Return the filename of the debug location for this value, which must be
    /// an LLVM `Instruction`, `lGlobalVariable`, or `Function`.
    ///
    /// # Details
    ///
    /// Retrieves the filename from the debug location associated with this value in LLVM IR.
    ///
    /// This function wraps the `LLVMGetDebugLocFilename` function from the LLVM core library. It returns the
    /// filename of the source code location associated with the debug information for the value represented by `self`.
    /// If the filename cannot be retrieved, the function returns `None`.
    ///
    /// # Returns
    ///
    /// Returns an `Option<String>`:
    /// - `Some(String)` containing the filename associated with the value's debug location if successful.
    /// - `None` if the filename cannot be retrieved.
    #[must_use]
    pub fn get_debug_loc_filename(&self) -> Option<String> {
        unsafe {
            let mut length = CUint::from(0_usize);
            let c_str = core::LLVMGetDebugLocFilename(self.0, &mut *length);
            if c_str.is_null() {
                return None;
            }
            Some(CStr::new(c_str).to_string())
        }
    }

    /// Return the line number of the debug location for this value, which must be
    /// an LLVM `Instruction`, `GlobalVariable`, or `Function`.
    ///
    /// # Details
    ///
    /// Retrieves the line number from the debug location associated with this value in LLVM IR.
    ///
    /// This function wraps the `LLVMGetDebugLocLine` function from the LLVM core library. It returns the
    /// line number of the source code location associated with the debug information for the value represented by `self`.
    /// This is useful for debugging and for tools that need to report precise source locations.
    ///
    /// # Returns
    ///
    /// Returns a `u32` representing the line number in the source code associated with this value's debug location.
    #[must_use]
    pub fn get_debug_loc_line(&self) -> u32 {
        unsafe { core::LLVMGetDebugLocLine(self.0) }
    }

    /// Return the column number of the debug location for this value, which must be
    /// an LLVM `Instruction`.
    ///
    /// # Details
    ///
    /// Retrieves the column number from the debug location associated with this value in LLVM IR.
    ///
    /// This function wraps the `LLVMGetDebugLocColumn` function from the LLVM core library. It returns the
    /// column number of the source code location associated with the debug information for the value represented by `self`.
    /// This is useful for debugging and for tools that need to report precise source locations.
    ///
    /// # Returns
    ///
    /// Returns a `u32` representing the column number in the source code associated with this value's debug location.
    #[must_use]
    pub fn get_debug_loc_column(&self) -> u32 {
        unsafe { core::LLVMGetDebugLocColumn(self.0) }
    }

    /// Advance a `Function` iterator to the next Function.
    ///
    /// Returns `None` if the iterator was already at the end and there are no more functions.
    ///
    /// # Details
    ///
    /// Retrieves the next function in the module relative to this function, if it exists.
    ///
    /// This function wraps the `LLVMGetNextFunction` function from the LLVM core library. It returns the
    /// next function in the module relative to the function represented by `self`. If there is no next
    /// function, the function returns `None`. This is useful for iterating over functions within a module in LLVM IR.
    ///
    /// # Returns
    ///
    /// Returns an `Option<ValueRef>`:
    /// - `Some(ValueRef)` containing the next function if it exists.
    /// - `None` if there is no next function in the module.
    #[must_use]
    pub fn get_next_function(&self) -> Option<Self> {
        unsafe {
            let next_func = core::LLVMGetNextFunction(self.0);
            if next_func.is_null() {
                None
            } else {
                Some(Self(next_func))
            }
        }
    }

    /// Decrement a `Function` iterator to the previous Function.
    ///
    /// Returns `None` if the iterator was already at the beginning and there are no previous functions.
    ///
    /// # Details
    ///
    /// Retrieves the previous function in the module relative to this function, if it exists.
    ///
    /// This function wraps the `LLVMGetPreviousFunction` function from the LLVM core library. It returns the
    /// previous function in the module relative to the function represented by `self`. If there is no previous
    /// function, the function returns `None`. This is useful for iterating over functions within a module in LLVM IR.
    ///
    /// # Returns
    ///
    /// Returns an `Option<ValueRef>`:
    /// - `Some(ValueRef)` containing the previous function if it exists.
    /// - `None` if there is no previous function in the module.
    #[must_use]
    pub fn get_previous_function(&self) -> Option<Self> {
        unsafe {
            let prev_func = core::LLVMGetPreviousFunction(self.0);
            if prev_func.is_null() {
                None
            } else {
                Some(Self(prev_func))
            }
        }
    }
}