use std::ffi::c_void;
use inkwell::module::Module;
use inkwell::values::FunctionValue;
use inkwell_internals::llvm_versions;
use super::{
FunctionAnalysisManager, LlvmFunctionPass, LlvmModulePass, ModuleAnalysisManager,
PreservedAnalyses,
};
pub struct ModulePassManager {
inner: *mut c_void,
}
impl ModulePassManager {
#[doc(hidden)]
pub unsafe fn from_raw(pass_manager: *mut c_void) -> Self {
Self {
inner: pass_manager,
}
}
pub fn add_pass<T>(&mut self, pass: T)
where
T: LlvmModulePass,
{
let pass = Box::new(pass);
extern "C" fn pass_deleter<T>(pass: *mut c_void) {
drop(unsafe { Box::<T>::from_raw(pass.cast()) })
}
extern "C" fn pass_entrypoint<T>(
pass: *mut c_void,
module: *mut c_void,
manager: *mut c_void,
) -> PreservedAnalyses
where
T: LlvmModulePass,
{
let pass = unsafe { Box::<T>::from_raw(pass.cast()) };
let mut module = unsafe { Module::new(module.cast()) };
let manager = unsafe { ModuleAnalysisManager::from_raw(manager, None) };
let preserve = pass.run_pass(&mut module, &manager);
Box::into_raw(pass);
std::mem::forget(module);
preserve
}
unsafe {
super::modulePassManagerAddPass(
self.inner,
Box::into_raw(pass).cast(),
pass_deleter::<T>,
pass_entrypoint::<T>,
)
}
}
#[llvm_versions(12.0..=latest)]
pub fn is_empty(&self) -> bool {
unsafe { super::modulePassManagerIsEmpty(self.inner) }
}
}
pub struct FunctionPassManager {
inner: *mut c_void,
}
impl FunctionPassManager {
#[doc(hidden)]
pub unsafe fn from_raw(pass_manager: *mut c_void) -> Self {
Self {
inner: pass_manager,
}
}
pub fn add_pass<T>(&mut self, pass: T)
where
T: LlvmFunctionPass,
{
let pass = Box::new(pass);
extern "C" fn pass_deleter<T>(pass: *mut c_void) {
drop(unsafe { Box::<T>::from_raw(pass.cast()) })
}
extern "C" fn pass_entrypoint<T>(
pass: *mut c_void,
function: *mut c_void,
manager: *mut c_void,
) -> PreservedAnalyses
where
T: LlvmFunctionPass,
{
let pass = unsafe { Box::<T>::from_raw(pass.cast()) };
let mut function = unsafe { FunctionValue::new(function.cast()).unwrap() };
let manager = unsafe { FunctionAnalysisManager::from_raw(manager, None) };
let preserve = pass.run_pass(&mut function, &manager);
Box::into_raw(pass);
#[allow(forgetting_copy_types)]
std::mem::forget(function);
preserve
}
unsafe {
super::functionPassManagerAddPass(
self.inner,
Box::into_raw(pass).cast(),
pass_deleter::<T>,
pass_entrypoint::<T>,
)
}
}
#[llvm_versions(12.0..=latest)]
pub fn is_empty(&self) -> bool {
unsafe { super::functionPassManagerIsEmpty(self.inner) }
}
}