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
use llvm_sys::core::{LLVMGetIntrinsicDeclaration, LLVMIntrinsicIsOverloaded, LLVMLookupIntrinsicID};
use llvm_sys::prelude::LLVMTypeRef;
use crate::module::Module;
use crate::types::{AsTypeRef, BasicTypeEnum};
use crate::values::FunctionValue;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Intrinsic {
id: u32,
}
/// A wrapper around LLVM intrinsic id
///
/// To call it you would need to create a declaration inside a module using [`Self::get_declaration()`].
impl Intrinsic {
/// Create an Intrinsic object from raw LLVM intrinsic id
///
/// SAFETY: the id is a valid LLVM intrinsic ID
pub(crate) unsafe fn new(id: u32) -> Self {
Self { id }
}
/// Find llvm intrinsic id from name
///
/// # Example
/// ```no_run
/// use inkwell::{intrinsics::Intrinsic, context::Context};
///
/// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap();
///
/// let context = Context::create();
/// let module = context.create_module("trap");
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let fn_value = module.add_function("trap", fn_type, None);
/// let entry = context.append_basic_block(fn_value, "entry");
///
/// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap();
///
/// builder.position_at_end(entry);
/// builder.build_call(trap_function, &[], "trap_call");
/// ```
pub fn find(name: &str) -> Option<Self> {
let id = unsafe { LLVMLookupIntrinsicID(name.as_ptr() as *const ::libc::c_char, name.len()) };
if id == 0 {
return None;
}
Some(unsafe { Intrinsic::new(id) })
}
/// Check if specified intrinsic is overloaded
///
/// Overloaded intrinsics need some argument types to be specified to declare them
pub fn is_overloaded(&self) -> bool {
unsafe { LLVMIntrinsicIsOverloaded(self.id) != 0 }
}
/// Create or insert the declaration of an intrinsic.
///
/// For overloaded intrinsics, parameter types must be provided to uniquely identify an overload.
///
/// # Example
/// ```no_run
/// use inkwell::{intrinsics::Intrinsic, context::Context};
///
/// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap();
///
/// let context = Context::create();
/// let module = context.create_module("trap");
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let fn_value = module.add_function("trap", fn_type, None);
/// let entry = context.append_basic_block(fn_value, "entry");
///
/// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap();
///
/// builder.position_at_end(entry);
/// builder.build_call(trap_function, &[], "trap_call");
/// ```
pub fn get_declaration<'ctx>(
&self,
module: &Module<'ctx>,
param_types: &[BasicTypeEnum],
) -> Option<FunctionValue<'ctx>> {
let mut param_types: Vec<LLVMTypeRef> = param_types.iter().map(|val| val.as_type_ref()).collect();
// param_types should be empty for non-overloaded intrinsics (I think?)
// for overloaded intrinsics they determine the overload used
if self.is_overloaded() && param_types.is_empty() {
// LLVM crashes otherwise
return None;
}
unsafe {
FunctionValue::new(LLVMGetIntrinsicDeclaration(
module.module.get(),
self.id,
param_types.as_mut_ptr(),
param_types.len(),
))
}
}
}