-
Notifications
You must be signed in to change notification settings - Fork 207
/
callable_value.rs
123 lines (111 loc) · 4.12 KB
/
callable_value.rs
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
use std::convert::TryFrom;
use either::Either;
use crate::values::AsValueRef;
use crate::values::{FunctionValue, PointerValue, AnyValue};
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::core::{LLVMGetTypeKind, LLVMGetElementType, LLVMTypeOf, LLVMGetReturnType};
use llvm_sys::LLVMTypeKind;
/// A value that can be called with the [`build_call`] instruction.
///
/// In practice, the `F : Into<CallableValue<'ctx>>` bound of [`build_call`] means it is
/// possible to pass a [`FunctionValue`] to [`build_call`] directly. It will be implicitly converted
/// into a `CallableValue`.
///
/// [`build_call`]: crate::builder::Builder::build_call
///
/// ```no_run
/// use inkwell::context::Context;
///
/// // A simple function which calls itself:
/// let context = Context::create();
/// let module = context.create_module("ret");
/// let builder = context.create_builder();
/// let i32_type = context.i32_type();
/// let fn_type = i32_type.fn_type(&[i32_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
/// let entry = context.append_basic_block(fn_value, "entry");
/// let i32_arg = fn_value.get_first_param().unwrap();
///
/// builder.position_at_end(entry);
///
/// let ret_val = builder.build_call(fn_value, &[i32_arg.into()], "call")
/// .try_as_basic_value()
/// .left()
/// .unwrap();
///
/// builder.build_return(Some(&ret_val));
/// ```
///
/// A [`PointerValue`] cannot be implicitly converted to a `CallableValue` because the pointer may
/// point to a non-function value. Instead we can use [`TryFrom`] to handle this failure case explicitly.
///
/// ```no_run
/// use std::convert::TryFrom;
/// use inkwell::context::Context;
/// use inkwell::values::CallableValue;
///
/// // A simple function which calls itself:
/// let context = Context::create();
/// let module = context.create_module("ret");
/// let builder = context.create_builder();
/// let i32_type = context.i32_type();
/// let fn_type = i32_type.fn_type(&[i32_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
/// let entry = context.append_basic_block(fn_value, "entry");
/// let i32_arg = fn_value.get_first_param().unwrap();
///
/// builder.position_at_end(entry);
///
/// // take a pointer to the function value
/// let fn_pointer_value = fn_value.as_global_value().as_pointer_value();
///
/// // convert that pointer value into a callable value
/// // explicitly handling the failure case (here with `unwrap`)
/// let callable_value = CallableValue::try_from(fn_pointer_value).unwrap();
///
/// let ret_val = builder.build_call(callable_value, &[i32_arg.into()], "call")
/// .try_as_basic_value()
/// .left()
/// .unwrap();
///
/// builder.build_return(Some(&ret_val));
/// ```
#[derive(Debug)]
pub struct CallableValue<'ctx>(Either<FunctionValue<'ctx>, PointerValue<'ctx>>);
impl<'ctx> AsValueRef for CallableValue<'ctx> {
fn as_value_ref(&self) -> LLVMValueRef {
use either::Either::*;
match self.0 {
Left(function) => function.as_value_ref(),
Right(pointer) => pointer.as_value_ref(),
}
}
}
impl<'ctx> AnyValue<'ctx> for CallableValue<'ctx> {}
impl<'ctx> CallableValue<'ctx> {
pub(crate) fn returns_void(&self) -> bool {
let return_type = unsafe {
LLVMGetTypeKind(LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(self.as_value_ref()))))
};
matches!(return_type, LLVMTypeKind::LLVMVoidTypeKind)
}
}
impl<'ctx> From<FunctionValue<'ctx>> for CallableValue<'ctx> {
fn from(value: FunctionValue<'ctx>) -> Self {
Self(Either::Left(value))
}
}
impl<'ctx> TryFrom<PointerValue<'ctx>> for CallableValue<'ctx> {
type Error = ();
fn try_from(value: PointerValue<'ctx>) -> Result<Self, Self::Error> {
// If using a pointer value, we must validate it's a valid function ptr
let value_ref = value.as_value_ref();
let ty_kind = unsafe { LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(value_ref))) };
let is_a_fn_ptr = matches!(ty_kind, LLVMTypeKind::LLVMFunctionTypeKind);
if is_a_fn_ptr {
Ok(Self(Either::Right(value)))
} else {
Err(())
}
}
}