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