inkwell/values/
traits.rs

1use llvm_sys::core::LLVMIsConstant;
2use llvm_sys::prelude::LLVMValueRef;
3
4#[llvm_versions(12..)]
5use llvm_sys::core::LLVMIsPoison;
6
7use std::fmt::Debug;
8
9use crate::support::LLVMString;
10use crate::types::{
11    FloatMathType, FloatType, IntMathType, IntType, PointerMathType, PointerType, ScalableVectorType, VectorType,
12};
13use crate::values::{
14    AggregateValueEnum, AnyValueEnum, ArrayValue, BasicValueEnum, BasicValueUse, CallSiteValue, FloatValue,
15    FunctionValue, GlobalValue, InstructionValue, IntValue, PhiValue, PointerValue, ScalableVectorValue, StructValue,
16    Value, VectorValue,
17};
18
19use super::{BasicMetadataValueEnum, MetadataValue};
20
21// This is an ugly privacy hack so that Type can stay private to this module
22// and so that super traits using this trait will be not be implementable
23// outside this library
24pub unsafe trait AsValueRef {
25    fn as_value_ref(&self) -> LLVMValueRef;
26}
27
28macro_rules! trait_value_set {
29    ($trait_name:ident: $($args:ident),*) => (
30        $(
31            unsafe impl<'ctx> $trait_name<'ctx> for $args<'ctx> {}
32        )*
33
34        // REVIEW: Possible encompassing methods to implement:
35        // as_instruction, is_sized, ge/set metadata methods
36    );
37}
38
39macro_rules! math_trait_value_set {
40    ($trait_name:ident: $(($value_type:ident => $base_type:ident)),*) => (
41        $(
42            unsafe impl<'ctx> $trait_name<'ctx> for $value_type<'ctx> {
43                type BaseType = $base_type<'ctx>;
44                unsafe fn new(value: LLVMValueRef) -> $value_type<'ctx> {
45                    unsafe {
46                        $value_type::new(value)
47                    }
48                }
49            }
50        )*
51    )
52}
53
54macro_rules! base_trait_value_set {
55    ($trait_name:ident: $($value_type:ident),*) => (
56        $(
57            unsafe impl<'ctx> $trait_name<'ctx> for $value_type<'ctx> {
58                unsafe fn new(value: LLVMValueRef) -> $value_type<'ctx> {
59                    unsafe {
60                        $value_type::new(value)
61                    }
62                }
63            }
64        )*
65    )
66}
67
68/// Represents an aggregate value, built on top of other values.
69pub unsafe trait AggregateValue<'ctx>: BasicValue<'ctx> {
70    /// Returns an enum containing a typed version of the `AggregateValue`.
71    fn as_aggregate_value_enum(&self) -> AggregateValueEnum<'ctx> {
72        unsafe { AggregateValueEnum::new(self.as_value_ref()) }
73    }
74
75    // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option?
76    // or is that only in bounds GEP
77    // REVIEW: Should this be AggregatePointerValue?
78    #[llvm_versions(..=14)]
79    fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> {
80        use llvm_sys::core::LLVMConstExtractValue;
81
82        unsafe {
83            BasicValueEnum::new(LLVMConstExtractValue(
84                self.as_value_ref(),
85                indexes.as_mut_ptr(),
86                indexes.len() as u32,
87            ))
88        }
89    }
90
91    // SubTypes: value should really be T in self: VectorValue<T> I think
92    #[llvm_versions(..=14)]
93    fn const_insert_value<BV: BasicValue<'ctx>>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> {
94        use llvm_sys::core::LLVMConstInsertValue;
95
96        unsafe {
97            BasicValueEnum::new(LLVMConstInsertValue(
98                self.as_value_ref(),
99                value.as_value_ref(),
100                indexes.as_mut_ptr(),
101                indexes.len() as u32,
102            ))
103        }
104    }
105}
106
107/// Represents a basic value, which can be used both by itself, or in an `AggregateValue`.
108pub unsafe trait BasicValue<'ctx>: AnyValue<'ctx> {
109    /// Returns an enum containing a typed version of the `BasicValue`.
110    fn as_basic_value_enum(&self) -> BasicValueEnum<'ctx> {
111        unsafe { BasicValueEnum::new(self.as_value_ref()) }
112    }
113
114    /// Most `BasicValue`s are the byproduct of an instruction
115    /// and so are convertible into an `InstructionValue`
116    fn as_instruction_value(&self) -> Option<InstructionValue<'ctx>> {
117        let value = unsafe { Value::new(self.as_value_ref()) };
118
119        if !value.is_instruction() {
120            return None;
121        }
122
123        unsafe { Some(InstructionValue::new(self.as_value_ref())) }
124    }
125
126    fn get_first_use(&self) -> Option<BasicValueUse<'ctx>> {
127        unsafe { Value::new(self.as_value_ref()).get_first_use() }
128    }
129
130    /// Sets the name of a `BasicValue`. If the value is a constant, this is a noop.
131    fn set_name(&self, name: &str) {
132        unsafe { Value::new(self.as_value_ref()).set_name(name) }
133    }
134
135    /// Returns true if this value is a constant.
136    fn is_const(&self) -> bool {
137        unsafe { LLVMIsConstant(self.as_value_ref()) == 1 }
138    }
139
140    // REVIEW: Possible encompassing methods to implement:
141    // get/set metadata
142}
143
144/// Represents a value which is permitted in integer math operations
145pub unsafe trait IntMathValue<'ctx>: BasicValue<'ctx> {
146    type BaseType: IntMathType<'ctx>;
147    unsafe fn new(value: LLVMValueRef) -> Self;
148}
149
150/// Represents a value which is permitted in floating point math operations
151pub unsafe trait FloatMathValue<'ctx>: BasicValue<'ctx> {
152    type BaseType: FloatMathType<'ctx>;
153    unsafe fn new(value: LLVMValueRef) -> Self;
154}
155
156pub unsafe trait PointerMathValue<'ctx>: BasicValue<'ctx> {
157    type BaseType: PointerMathType<'ctx>;
158    unsafe fn new(value: LLVMValueRef) -> Self;
159}
160
161/// Represents a value which is permitted in vector operations, either fixed or scalable
162pub unsafe trait VectorBaseValue<'ctx>: BasicValue<'ctx> {
163    unsafe fn new(value: LLVMValueRef) -> Self;
164}
165
166// REVIEW: print_to_string might be a good candidate to live here?
167/// Defines any struct wrapping an LLVM value.
168pub unsafe trait AnyValue<'ctx>: AsValueRef + Debug {
169    /// Returns an enum containing a typed version of `AnyValue`.
170    fn as_any_value_enum(&self) -> AnyValueEnum<'ctx> {
171        unsafe { AnyValueEnum::new(self.as_value_ref()) }
172    }
173
174    /// Prints a value to a `LLVMString`
175    fn print_to_string(&self) -> LLVMString {
176        unsafe { Value::new(self.as_value_ref()).print_to_string() }
177    }
178
179    /// Returns whether the value is `poison`
180    #[llvm_versions(12..)]
181    fn is_poison(&self) -> bool {
182        unsafe { LLVMIsPoison(self.as_value_ref()) == 1 }
183    }
184}
185
186trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
187trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, BasicMetadataValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, GlobalValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, ScalableVectorValue, InstructionValue, CallSiteValue, MetadataValue}
188trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, GlobalValue, StructValue, PointerValue, VectorValue, ScalableVectorValue}
189math_trait_value_set! {IntMathValue: (IntValue => IntType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType), (PointerValue => IntType)}
190math_trait_value_set! {FloatMathValue: (FloatValue => FloatType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType)}
191math_trait_value_set! {PointerMathValue: (PointerValue => PointerType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType)}
192base_trait_value_set! {VectorBaseValue: VectorValue, ScalableVectorValue}