Skip to content

Commit

Permalink
Allow customizing MCJIT Compiler options on execution engine creation
Browse files Browse the repository at this point in the history
Workaround for: TheDan64#296
  • Loading branch information
semoro committed Jan 25, 2022
1 parent a24642d commit f0b3f46
Showing 1 changed file with 59 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef};
use llvm_sys::LLVMLinkage;
#[llvm_versions(7.0..=latest)]
use llvm_sys::LLVMModuleFlagBehavior;
use llvm_sys::execution_engine::{LLVMMCJITCompilerOptions, LLVMMCJITMemoryManagerRef, LLVMCreateMCJITCompilerForModule, LLVMInitializeMCJITCompilerOptions};

use std::cell::{Cell, RefCell, Ref};
use std::ffi::CStr;
Expand Down Expand Up @@ -537,6 +538,64 @@ impl<'ctx> Module<'ctx> {
Ok(execution_engine)
}

/// Creates a JIT `ExecutionEngine` from this `Module`, while allowing to customize MCJIT options.
///
/// # Example
/// ```no_run
/// use inkwell::OptimizationLevel;
/// use inkwell::context::Context;
/// use inkwell::module::Module;
/// use inkwell::targets::{InitializationConfig, Target};
///
/// Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
///
/// let context = Context::create();
/// let module = context.create_module("my_module");
/// let execution_engine = module.create_jit_execution_engine_with_options(|opts| { opts.OptLevel = OptimizationLevel::Default as u32 }).unwrap();
///
/// assert_eq!(*module.get_context(), context);
/// ```
pub fn create_jit_execution_engine_with_options<F: FnOnce(&mut LLVMMCJITCompilerOptions)>(&self, customize_options: F) -> Result<ExecutionEngine<'ctx>, LLVMString> {
Target::initialize_native(&InitializationConfig::default())
.map_err(|mut err_string| {
err_string.push('\0');

LLVMString::create_from_str(&err_string)
})?;

if self.owned_by_ee.borrow().is_some() {
let string = "This module is already owned by an ExecutionEngine.\0";
return Err(LLVMString::create_from_str(string));
}

let mut execution_engine = MaybeUninit::uninit();
let mut err_string = MaybeUninit::uninit();

let code = unsafe {
// Takes ownership of module
let mut options: LLVMMCJITCompilerOptions = std::mem::zeroed();
LLVMInitializeMCJITCompilerOptions(
&mut options,
std::mem::size_of::<LLVMMCJITCompilerOptions>()
);
customize_options(&mut options);
LLVMCreateMCJITCompilerForModule(execution_engine.as_mut_ptr(), self.module.get(), &mut options, std::mem::size_of::<LLVMMCJITCompilerOptions>(), err_string.as_mut_ptr())
};

if code == 1 {
unsafe {
return Err(LLVMString::new(err_string.assume_init()));
}
}

let execution_engine = unsafe { execution_engine.assume_init() };
let execution_engine = unsafe { ExecutionEngine::new(Rc::new(execution_engine), true) };

*self.owned_by_ee.borrow_mut() = Some(execution_engine.clone());

Ok(execution_engine)
}

/// Creates a `GlobalValue` based on a type in an address space.
///
/// # Example
Expand Down

0 comments on commit f0b3f46

Please sign in to comment.