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
#[llvm_versions(9..)]
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()`].
#[llvm_versions(9..)]
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;
}
let res = unsafe {
FunctionValue::new(LLVMGetIntrinsicDeclaration(
module.module.get(),
self.id,
param_types.as_mut_ptr(),
param_types.len(),
))
};
res
}
}