use std::ffi::c_void;
use inkwell::module::Module;
use inkwell::values::{AsValueRef, FunctionValue};
use inkwell::LLVMReference;
use crate::{LlvmFunctionAnalysis, LlvmModuleAnalysis};
pub struct FunctionAnalysisManager {
inner: *mut c_void,
from_analysis_id: Option<crate::AnalysisKey>,
}
impl FunctionAnalysisManager {
#[doc(hidden)]
pub unsafe fn from_raw(
inner: *mut c_void,
from_analysis_id: Option<crate::AnalysisKey>,
) -> Self {
Self {
inner,
from_analysis_id,
}
}
pub fn get_result<'a, A>(&self, function: &FunctionValue<'a>) -> &A::Result
where
A: crate::LlvmFunctionAnalysis,
{
let id = A::id();
assert!(
!matches!(self.from_analysis_id, Some(n) if id == n),
"Analysis cannot request its own result"
);
unsafe {
let res =
crate::get_function_analysis_result(self.inner, id, function.as_value_ref().cast());
Box::leak(Box::from_raw(res.cast()))
}
}
pub fn get_cached_result<'a, A>(&self, function: &FunctionValue<'a>) -> Option<&A::Result>
where
A: crate::LlvmFunctionAnalysis,
{
let id = A::id();
assert!(
!matches!(self.from_analysis_id, Some(n) if id == n),
"Analysis cannot request its own result"
);
unsafe {
let res = crate::get_function_analysis_cached_result(
self.inner,
id,
function.as_value_ref().cast(),
);
(!res.is_null()).then_some(Box::leak(Box::from_raw(res.cast())))
}
}
pub fn register_pass<T>(&mut self, pass: T)
where
T: LlvmFunctionAnalysis,
{
let pass = Box::new(pass);
extern "C" fn result_deleter<T>(data: *mut c_void)
where
T: LlvmFunctionAnalysis,
{
drop(unsafe { Box::<<T as LlvmFunctionAnalysis>::Result>::from_raw(data.cast()) })
}
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,
res: *mut *mut c_void,
res_deleter: *mut extern "C" fn(*mut c_void),
) where
T: LlvmFunctionAnalysis,
{
let pass = unsafe { Box::<T>::from_raw(pass.cast()) };
let function = unsafe { FunctionValue::new(function.cast()).unwrap() };
let manager = unsafe { FunctionAnalysisManager::from_raw(manager, Some(T::id())) };
let data = pass.run_analysis(&function, &manager);
let data = Box::new(data);
unsafe {
*res = Box::<<T as LlvmFunctionAnalysis>::Result>::into_raw(data).cast();
*res_deleter = result_deleter::<T>;
}
Box::into_raw(pass);
#[allow(clippy::forget_copy)]
std::mem::forget(function);
}
let success = unsafe {
super::functionAnalysisManagerRegisterPass(
self.inner,
Box::into_raw(pass).cast(),
pass_deleter::<T>,
pass_entrypoint::<T>,
T::id(),
)
};
assert!(success, "analysis already registered");
}
}
pub struct ModuleAnalysisManager {
inner: *mut c_void,
from_analysis_id: Option<crate::AnalysisKey>,
}
impl ModuleAnalysisManager {
#[doc(hidden)]
pub unsafe fn from_raw(
inner: *mut c_void,
from_analysis_id: Option<crate::AnalysisKey>,
) -> Self {
Self {
inner,
from_analysis_id,
}
}
pub fn get_result<'a, A>(&self, module: &Module<'a>) -> &A::Result
where
A: crate::LlvmModuleAnalysis,
{
let id = A::id();
assert!(
!matches!(self.from_analysis_id, Some(n) if id == n),
"Analysis cannot request its own result"
);
unsafe {
let res =
crate::get_module_analysis_result(self.inner, A::id(), module.get_ref().cast());
Box::leak(Box::from_raw(res.cast()))
}
}
pub fn get_cached_result<'a, A>(&self, module: &Module<'a>) -> Option<&A::Result>
where
A: crate::LlvmModuleAnalysis,
{
let id = A::id();
assert!(
!matches!(self.from_analysis_id, Some(n) if id == n),
"Analysis cannot request its own result"
);
unsafe {
let res = crate::get_module_analysis_cached_result(
self.inner,
A::id(),
module.get_ref().cast(),
);
(!res.is_null()).then_some(Box::leak(Box::from_raw(res.cast())))
}
}
pub fn get_function_analysis_manager_proxy<'a>(
&self,
module: &Module<'a>,
) -> FunctionAnalysisManagerProxy {
let proxy = crate::get_function_analysis_manager_module_proxy(self.inner, unsafe {
module.get_ref().cast()
});
FunctionAnalysisManagerProxy { inner: proxy }
}
pub fn register_pass<T>(&mut self, pass: T)
where
T: LlvmModuleAnalysis,
{
let pass = Box::new(pass);
extern "C" fn result_deleter<T>(data: *mut c_void)
where
T: LlvmModuleAnalysis,
{
drop(unsafe { Box::<<T as LlvmModuleAnalysis>::Result>::from_raw(data.cast()) })
}
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,
res: *mut *mut c_void,
res_deleter: *mut extern "C" fn(*mut c_void),
) where
T: LlvmModuleAnalysis,
{
let pass = unsafe { Box::<T>::from_raw(pass.cast()) };
let module = unsafe { Module::new(module.cast()) };
let manager = unsafe { ModuleAnalysisManager::from_raw(manager, Some(T::id())) };
let data = pass.run_analysis(&module, &manager);
let data = Box::new(data);
unsafe {
*res = Box::<<T as LlvmModuleAnalysis>::Result>::into_raw(data).cast();
*res_deleter = result_deleter::<T>;
}
Box::into_raw(pass);
std::mem::forget(module);
}
let success = unsafe {
super::moduleAnalysisManagerRegisterPass(
self.inner,
Box::into_raw(pass).cast(),
pass_deleter::<T>,
pass_entrypoint::<T>,
T::id(),
)
};
assert!(success, "analysis already registered");
}
}
pub struct FunctionAnalysisManagerProxy {
inner: *mut c_void,
}
impl FunctionAnalysisManagerProxy {
pub fn get_manager(&self) -> FunctionAnalysisManager {
let manager = crate::get_function_analysis_manager(self.inner);
FunctionAnalysisManager {
inner: manager,
from_analysis_id: None,
}
}
}