Skip to content

Commit

Permalink
Simplified Module & ExecutionEngine API relationship. Fixed #27
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDan64 committed Nov 10, 2017
1 parent c426075 commit e934a51
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 105 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extern crate inkwell;

```rust
use inkwell::context::Context;
use inkwell::OptimizationLevel;
use inkwell::targets::{InitializationConfig, Target};
use std::mem::transmute;

Expand All @@ -49,8 +50,7 @@ Target::initialize_native(&InitializationConfig::default())?;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
let execution_engine = module.create_jit_execution_engine(0)?;
let module = execution_engine.get_module_at(0);
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;

let i64_type = context.i64_type();
let fn_type = i64_type.fn_type(&[&i64_type, &i64_type, &i64_type], false);
Expand Down
4 changes: 3 additions & 1 deletion src/basic_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use values::{FunctionValue, InstructionValue};

use std::fmt;
use std::ffi::{CStr, CString};
use std::rc::Rc;

// Apparently BasicBlocks count as LabelTypeKinds, which is
// why they're allow to be casted to values?
Expand Down Expand Up @@ -133,7 +134,8 @@ impl BasicBlock {
LLVMGetTypeContext(LLVMTypeOf(LLVMBasicBlockAsValue(self.basic_block)))
};

ContextRef::new(Context::new(context))
// REVIEW: This probably should be somehow using the existing context Rc
ContextRef::new(Context::new(Rc::new(context)))
}
}

Expand Down
72 changes: 40 additions & 32 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ use std::ffi::{CStr, CString};
use std::mem::forget;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;

// From Docs: A single context is not thread safe.
// However, different contexts can execute on different threads simultaneously.
#[derive(Debug, PartialEq, Eq)]
pub struct Context {
pub(crate) context: LLVMContextRef,
pub(crate) context: Rc<LLVMContextRef>,
}

impl Context {
pub(crate) fn new(context: LLVMContextRef) -> Self {
pub(crate) fn new(context: Rc<LLVMContextRef>) -> Self {
assert!(!context.is_null());

Context {
context: context
context,
}
}

Expand All @@ -44,7 +45,7 @@ impl Context {
LLVMContextCreate()
};

Context::new(context)
Context::new(Rc::new(context))
}

/// Creates a `ContextRef` which references the global context singleton.
Expand All @@ -61,7 +62,7 @@ impl Context {
LLVMGetGlobalContext()
};

ContextRef::new(Context::new(context))
ContextRef::new(Context::new(Rc::new(context)))
}

/// Creates a new `Builder` for a `Context`.
Expand All @@ -76,7 +77,7 @@ impl Context {
/// ```
pub fn create_builder(&self) -> Builder {
let builder = unsafe {
LLVMCreateBuilderInContext(self.context)
LLVMCreateBuilderInContext(*self.context)
};

Builder::new(builder)
Expand All @@ -96,10 +97,10 @@ impl Context {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let module = unsafe {
LLVMModuleCreateWithNameInContext(c_string.as_ptr(), self.context)
LLVMModuleCreateWithNameInContext(c_string.as_ptr(), *self.context)
};

Module::new(module)
Module::new(module, Some(&self))
}

// REVIEW: I haven't yet been able to find docs or other wrappers that confirm, but my suspicion
Expand All @@ -111,13 +112,13 @@ impl Context {
let mut err_str = ptr::null_mut();

let code = unsafe {
LLVMParseIRInContext(self.context, memory_buffer.memory_buffer, &mut module, &mut err_str)
LLVMParseIRInContext(*self.context, memory_buffer.memory_buffer, &mut module, &mut err_str)
};

forget(memory_buffer);

if code == 0 {
return Ok(Module::new(module));
return Ok(Module::new(module, Some(&self)));
}

let rust_str = unsafe {
Expand All @@ -133,47 +134,47 @@ impl Context {

pub fn void_type(&self) -> VoidType {
let void_type = unsafe {
LLVMVoidTypeInContext(self.context)
LLVMVoidTypeInContext(*self.context)
};

VoidType::new(void_type)
}

pub fn bool_type(&self) -> IntType {
let bool_type = unsafe {
LLVMInt1TypeInContext(self.context)
LLVMInt1TypeInContext(*self.context)
};

IntType::new(bool_type)
}

pub fn i8_type(&self) -> IntType {
let i8_type = unsafe {
LLVMInt8TypeInContext(self.context)
LLVMInt8TypeInContext(*self.context)
};

IntType::new(i8_type)
}

pub fn i16_type(&self) -> IntType {
let i16_type = unsafe {
LLVMInt16TypeInContext(self.context)
LLVMInt16TypeInContext(*self.context)
};

IntType::new(i16_type)
}

pub fn i32_type(&self) -> IntType {
let i32_type = unsafe {
LLVMInt32TypeInContext(self.context)
LLVMInt32TypeInContext(*self.context)
};

IntType::new(i32_type)
}

pub fn i64_type(&self) -> IntType {
let i64_type = unsafe {
LLVMInt64TypeInContext(self.context)
LLVMInt64TypeInContext(*self.context)
};

IntType::new(i64_type)
Expand All @@ -188,47 +189,47 @@ impl Context {

pub fn custom_width_int_type(&self, bits: u32) -> IntType {
let int_type = unsafe {
LLVMIntTypeInContext(self.context, bits)
LLVMIntTypeInContext(*self.context, bits)
};

IntType::new(int_type)
}

pub fn f16_type(&self) -> FloatType {
let f16_type = unsafe {
LLVMHalfTypeInContext(self.context)
LLVMHalfTypeInContext(*self.context)
};

FloatType::new(f16_type)
}

pub fn f32_type(&self) -> FloatType {
let f32_type = unsafe {
LLVMFloatTypeInContext(self.context)
LLVMFloatTypeInContext(*self.context)
};

FloatType::new(f32_type)
}

pub fn f64_type(&self) -> FloatType {
let f64_type = unsafe {
LLVMDoubleTypeInContext(self.context)
LLVMDoubleTypeInContext(*self.context)
};

FloatType::new(f64_type)
}

pub fn f128_type(&self) -> FloatType {
let f128_type = unsafe {
LLVMFP128TypeInContext(self.context)
LLVMFP128TypeInContext(*self.context)
};

FloatType::new(f128_type)
}

pub fn ppc_f128_type(&self) -> FloatType {
let f128_type = unsafe {
LLVMPPCFP128TypeInContext(self.context)
LLVMPPCFP128TypeInContext(*self.context)
};

FloatType::new(f128_type)
Expand All @@ -240,7 +241,7 @@ impl Context {
.map(|val| val.as_type_ref())
.collect();
let struct_type = unsafe {
LLVMStructTypeInContext(self.context, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32)
LLVMStructTypeInContext(*self.context, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32)
};

StructType::new(struct_type)
Expand All @@ -250,7 +251,7 @@ impl Context {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let struct_type = unsafe {
LLVMStructCreateNamed(self.context, c_string.as_ptr())
LLVMStructCreateNamed(*self.context, c_string.as_ptr())
};

StructType::new(struct_type)
Expand All @@ -260,7 +261,7 @@ impl Context {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let bb = unsafe {
LLVMAppendBasicBlockInContext(self.context, function.as_value_ref(), c_string.as_ptr())
LLVMAppendBasicBlockInContext(*self.context, function.as_value_ref(), c_string.as_ptr())
};

BasicBlock::new(bb).expect("Appending basic block should never fail")
Expand All @@ -284,7 +285,7 @@ impl Context {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let bb = unsafe {
LLVMInsertBasicBlockInContext(self.context, basic_block.basic_block, c_string.as_ptr())
LLVMInsertBasicBlockInContext(*self.context, basic_block.basic_block, c_string.as_ptr())
};

BasicBlock::new(bb).expect("Prepending basic block should never fail")
Expand All @@ -295,7 +296,7 @@ impl Context {
.map(|val| val.as_value_ref())
.collect();
let value = unsafe {
LLVMConstStructInContext(self.context, args.as_mut_ptr(), args.len() as u32, packed as i32)
LLVMConstStructInContext(*self.context, args.as_mut_ptr(), args.len() as u32, packed as i32)
};

StructValue::new(value)
Expand All @@ -308,7 +309,7 @@ impl Context {
.map(|val| val.as_value_ref())
.collect();
let metadata_value = unsafe {
LLVMMDNodeInContext(self.context, tuple_values.as_mut_ptr(), tuple_values.len() as u32)
LLVMMDNodeInContext(*self.context, tuple_values.as_mut_ptr(), tuple_values.len() as u32)
};

MetadataValue::new(metadata_value)
Expand All @@ -319,30 +320,36 @@ impl Context {
let c_string = CString::new(string).expect("Conversion to CString failed unexpectedly");

let metadata_value = unsafe {
LLVMMDStringInContext(self.context, c_string.as_ptr(), string.len() as u32)
LLVMMDStringInContext(*self.context, c_string.as_ptr(), string.len() as u32)
};

MetadataValue::new(metadata_value)
}

pub fn get_kind_id(&self, key: &str) -> u32 {
unsafe {
LLVMGetMDKindIDInContext(self.context, key.as_ptr() as *const i8, key.len() as u32)
LLVMGetMDKindIDInContext(*self.context, key.as_ptr() as *const i8, key.len() as u32)
}
}
}

impl Drop for Context {
fn drop(&mut self) {
unsafe {
LLVMContextDispose(self.context);
if Rc::strong_count(&self.context) == 1 {
unsafe {
LLVMContextDispose(*self.context);
}
}
}
}

// Alternate strategy would be to just define ownership parameter
// on Context, and only call destructor if true. Not sure of pros/cons
// compared to this approach other than not needing Deref trait's ugly syntax
// REVIEW: Now that Contexts are ref counted, it may not be necessary to
// have this ContextRef type, however Global Contexts throw a wrench in that
// a bit as it is a special case. get_context() methods as well since they do
// not have access to the original Rc.
#[derive(Debug, PartialEq, Eq)]
pub struct ContextRef {
context: Option<Context>,
Expand All @@ -366,6 +373,7 @@ impl Deref for ContextRef {

impl Drop for ContextRef {
fn drop(&mut self) {
// REVIEW: If you forget an Rc type like Context, does that mean it never gets decremented?
forget(self.context.take());
}
}
Loading

0 comments on commit e934a51

Please sign in to comment.