Skip to main content

inkwell/values/
traits.rs

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