inkwell/intrinsics.rs
1use llvm_sys::core::{LLVMGetIntrinsicDeclaration, LLVMIntrinsicIsOverloaded, LLVMLookupIntrinsicID};
2use llvm_sys::prelude::LLVMTypeRef;
3
4use crate::module::Module;
5use crate::types::{AsTypeRef, BasicTypeEnum};
6use crate::values::FunctionValue;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9pub struct Intrinsic {
10 id: u32,
11}
12
13/// A wrapper around LLVM intrinsic id
14///
15/// To call it you would need to create a declaration inside a module using [`Self::get_declaration()`].
16impl Intrinsic {
17 /// Create an Intrinsic object from raw LLVM intrinsic id
18 ///
19 /// SAFETY: the id is a valid LLVM intrinsic ID
20 pub(crate) unsafe fn new(id: u32) -> Self {
21 Self { id }
22 }
23
24 /// Find llvm intrinsic id from name
25 ///
26 /// # Example
27 /// ```no_run
28 /// use inkwell::{intrinsics::Intrinsic, context::Context};
29 ///
30 /// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap();
31 ///
32 /// let context = Context::create();
33 /// let module = context.create_module("trap");
34 /// let builder = context.create_builder();
35 /// let void_type = context.void_type();
36 /// let fn_type = void_type.fn_type(&[], false);
37 /// let fn_value = module.add_function("trap", fn_type, None);
38 /// let entry = context.append_basic_block(fn_value, "entry");
39 ///
40 /// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap();
41 ///
42 /// builder.position_at_end(entry);
43 /// builder.build_call(trap_function, &[], "trap_call");
44 /// ```
45 pub fn find(name: &str) -> Option<Self> {
46 let id = unsafe { LLVMLookupIntrinsicID(name.as_ptr() as *const ::libc::c_char, name.len()) };
47
48 if id == 0 {
49 return None;
50 }
51
52 Some(unsafe { Intrinsic::new(id) })
53 }
54
55 /// Check if specified intrinsic is overloaded
56 ///
57 /// Overloaded intrinsics need some argument types to be specified to declare them
58 pub fn is_overloaded(&self) -> bool {
59 unsafe { LLVMIntrinsicIsOverloaded(self.id) != 0 }
60 }
61
62 /// Create or insert the declaration of an intrinsic.
63 ///
64 /// For overloaded intrinsics, parameter types must be provided to uniquely identify an overload.
65 ///
66 /// # Example
67 /// ```no_run
68 /// use inkwell::{intrinsics::Intrinsic, context::Context};
69 ///
70 /// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap();
71 ///
72 /// let context = Context::create();
73 /// let module = context.create_module("trap");
74 /// let builder = context.create_builder();
75 /// let void_type = context.void_type();
76 /// let fn_type = void_type.fn_type(&[], false);
77 /// let fn_value = module.add_function("trap", fn_type, None);
78 /// let entry = context.append_basic_block(fn_value, "entry");
79 ///
80 /// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap();
81 ///
82 /// builder.position_at_end(entry);
83 /// builder.build_call(trap_function, &[], "trap_call");
84 /// ```
85 pub fn get_declaration<'ctx>(
86 &self,
87 module: &Module<'ctx>,
88 param_types: &[BasicTypeEnum],
89 ) -> Option<FunctionValue<'ctx>> {
90 let mut param_types: Vec<LLVMTypeRef> = param_types.iter().map(|val| val.as_type_ref()).collect();
91
92 // param_types should be empty for non-overloaded intrinsics (I think?)
93 // for overloaded intrinsics they determine the overload used
94
95 if self.is_overloaded() && param_types.is_empty() {
96 // LLVM crashes otherwise
97 return None;
98 }
99
100 unsafe {
101 FunctionValue::new(LLVMGetIntrinsicDeclaration(
102 module.as_mut_ptr(),
103 self.id,
104 param_types.as_mut_ptr(),
105 param_types.len(),
106 ))
107 }
108 }
109}