llvm_plugin_inkwell/values/
struct_value.rs

1use either::{
2    Either,
3    Either::{Left, Right},
4};
5use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMIsABasicBlock, LLVMSetOperand, LLVMValueAsBasicBlock};
6use llvm_sys::prelude::LLVMValueRef;
7
8use std::ffi::CStr;
9use std::fmt::{self, Display};
10
11use crate::basic_block::BasicBlock;
12use crate::types::StructType;
13use crate::values::traits::AsValueRef;
14use crate::values::{BasicValue, BasicValueEnum, InstructionValue, Value};
15
16use super::AnyValue;
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
19pub struct StructValue<'ctx> {
20    struct_value: Value<'ctx>,
21}
22
23impl<'ctx> StructValue<'ctx> {
24    pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
25        assert!(!value.is_null());
26
27        StructValue {
28            struct_value: Value::new(value),
29        }
30    }
31
32    /// Gets the name of a `StructValue`. If the value is a constant, this will
33    /// return an empty string.
34    pub fn get_name(&self) -> &CStr {
35        self.struct_value.get_name()
36    }
37
38    /// Get name of the `StructValue`.
39    pub fn set_name(&self, name: &str) {
40        self.struct_value.set_name(name)
41    }
42
43    pub fn get_type(self) -> StructType<'ctx> {
44        unsafe { StructType::new(self.struct_value.get_type()) }
45    }
46
47    pub fn is_null(self) -> bool {
48        self.struct_value.is_null()
49    }
50
51    pub fn is_undef(self) -> bool {
52        self.struct_value.is_undef()
53    }
54
55    pub fn print_to_stderr(self) {
56        self.struct_value.print_to_stderr()
57    }
58
59    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
60        self.struct_value.as_instruction()
61    }
62
63    pub fn get_num_operands(self) -> u32 {
64        unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 }
65    }
66
67    pub fn set_operand<BV: BasicValue<'ctx>>(self, index: u32, val: BV) -> bool {
68        let num_operands = self.get_num_operands();
69
70        if index >= num_operands {
71            return false;
72        }
73
74        unsafe { LLVMSetOperand(self.as_value_ref(), index, val.as_value_ref()) }
75
76        true
77    }
78
79    pub fn get_operand(self, index: u32) -> Option<Either<BasicValueEnum<'ctx>, BasicBlock<'ctx>>> {
80        let num_operands = self.get_num_operands();
81
82        if index >= num_operands {
83            return None;
84        }
85
86        let operand = unsafe { LLVMGetOperand(self.as_value_ref(), index) };
87
88        if operand.is_null() {
89            return None;
90        }
91
92        let is_basic_block = unsafe { !LLVMIsABasicBlock(operand).is_null() };
93
94        if is_basic_block {
95            let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(operand)) };
96
97            Some(Right(bb.expect("BasicBlock should always be valid")))
98        } else {
99            Some(Left(unsafe { BasicValueEnum::new(operand) }))
100        }
101    }
102
103    pub fn replace_all_uses_with(self, other: StructValue<'ctx>) {
104        self.struct_value.replace_all_uses_with(other.as_value_ref())
105    }
106}
107
108unsafe impl AsValueRef for StructValue<'_> {
109    fn as_value_ref(&self) -> LLVMValueRef {
110        self.struct_value.value
111    }
112}
113
114impl Display for StructValue<'_> {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        write!(f, "{}", self.print_to_string())
117    }
118}