llvm_plugin_inkwell/values/
traits.rs

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