Skip to content

Commit

Permalink
Merge pull request rust-lang#123 from TheDan64/feature/context_lifetime
Browse files Browse the repository at this point in the history
Add context lifetime to most LLVM types for memory safety+
  • Loading branch information
TheDan64 authored Nov 16, 2019
2 parents 5f9c584 + 569e98d commit 4aeb597
Show file tree
Hide file tree
Showing 50 changed files with 1,788 additions and 1,751 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ experimental = ["static-alloc"]

[dependencies]
either = "1.5"
enum-methods = "0.0.8"
inkwell_internals = { path = "./internal_macros", version = "0.1.0" }
libc = "0.2"
llvm-sys = "80.1"
once_cell = "1.2"
parking_lot = "0.9"
regex = "1"
static-alloc = { version = "0.1", optional = true }
lazy_static = "1.3.0"

[badges]
travis-ci = { repository = "TheDan64/inkwell" }
Expand Down
12 changes: 6 additions & 6 deletions examples/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ use std::error::Error;
/// do `unsafe` operations internally.
type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64;

fn jit_compile_sum(
context: &Context,
module: &Module,
builder: &Builder,
execution_engine: &ExecutionEngine,
fn jit_compile_sum<'ctx>(
context: &'ctx Context,
module: &Module<'ctx>,
builder: &Builder<'ctx>,
execution_engine: &ExecutionEngine<'ctx>,
) -> Option<JitFunction<SumFunc>> {
let i64_type = context.i64_type();
let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);

let function = module.add_function("sum", fn_type, None);
let basic_block = context.append_basic_block(&function, "entry");
let basic_block = context.append_basic_block(function, "entry");

builder.position_at_end(&basic_block);

Expand Down
48 changes: 27 additions & 21 deletions examples/kaleidoscope/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,32 +836,32 @@ impl<'a> Parser<'a> {
// ======================================================================================

/// Defines the `Expr` compiler.
pub struct Compiler<'a> {
pub context: &'a Context,
pub builder: &'a Builder,
pub fpm: &'a PassManager<FunctionValue>,
pub module: &'a Module,
pub struct Compiler<'a, 'ctx> {
pub context: &'ctx Context,
pub builder: &'a Builder<'ctx>,
pub fpm: &'a PassManager<FunctionValue<'ctx>>,
pub module: &'a Module<'ctx>,
pub function: &'a Function,

variables: HashMap<String, PointerValue>,
fn_value_opt: Option<FunctionValue>
variables: HashMap<String, PointerValue<'ctx>>,
fn_value_opt: Option<FunctionValue<'ctx>>
}

impl<'a> Compiler<'a> {
impl<'a, 'ctx> Compiler<'a, 'ctx> {
/// Gets a defined function given its name.
#[inline]
fn get_function(&self, name: &str) -> Option<FunctionValue> {
fn get_function(&self, name: &str) -> Option<FunctionValue<'ctx>> {
self.module.get_function(name)
}

/// Returns the `FunctionValue` representing the function being compiled.
#[inline]
fn fn_value(&self) -> FunctionValue {
fn fn_value(&self) -> FunctionValue<'ctx> {
self.fn_value_opt.unwrap()
}

/// Creates a new stack allocation instruction in the entry block of the function.
fn create_entry_block_alloca(&self, name: &str) -> PointerValue {
fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> {
let builder = self.context.create_builder();

let entry = self.fn_value().get_first_basic_block().unwrap();
Expand All @@ -875,7 +875,7 @@ impl<'a> Compiler<'a> {
}

/// Compiles the specified `Expr` into an LLVM `FloatValue`.
fn compile_expr(&mut self, expr: &Expr) -> Result<FloatValue, &'static str> {
fn compile_expr(&mut self, expr: &Expr) -> Result<FloatValue<'ctx>, &'static str> {
match *expr {
Expr::Number(nb) => Ok(self.context.f64_type().const_float(nb)),

Expand Down Expand Up @@ -1002,9 +1002,9 @@ impl<'a> Compiler<'a> {
let cond = self.builder.build_float_compare(FloatPredicate::ONE, cond, zero_const, "ifcond");

// build branch
let then_bb = self.context.append_basic_block(&parent, "then");
let else_bb = self.context.append_basic_block(&parent, "else");
let cont_bb = self.context.append_basic_block(&parent, "ifcont");
let then_bb = self.context.append_basic_block(parent, "then");
let else_bb = self.context.append_basic_block(parent, "else");
let cont_bb = self.context.append_basic_block(parent, "ifcont");

self.builder.build_conditional_branch(cond, &then_bb, &else_bb);

Expand Down Expand Up @@ -1044,7 +1044,7 @@ impl<'a> Compiler<'a> {
self.builder.build_store(start_alloca, start);

// go from current block to loop block
let loop_bb = self.context.append_basic_block(&parent, "loop");
let loop_bb = self.context.append_basic_block(parent, "loop");

self.builder.build_unconditional_branch(&loop_bb);
self.builder.position_at_end(&loop_bb);
Expand All @@ -1071,7 +1071,7 @@ impl<'a> Compiler<'a> {
self.builder.build_store(start_alloca, next_var);

let end_cond = self.builder.build_float_compare(FloatPredicate::ONE, end_cond, self.context.f64_type().const_float(0.0), "loopcond");
let after_bb = self.context.append_basic_block(&parent, "afterloop");
let after_bb = self.context.append_basic_block(parent, "afterloop");

self.builder.build_conditional_branch(end_cond, &loop_bb, &after_bb);
self.builder.position_at_end(&after_bb);
Expand All @@ -1088,7 +1088,7 @@ impl<'a> Compiler<'a> {
}

/// Compiles the specified `Prototype` into an extern LLVM `FunctionValue`.
fn compile_prototype(&self, proto: &Prototype) -> Result<FunctionValue, &'static str> {
fn compile_prototype(&self, proto: &Prototype) -> Result<FunctionValue<'ctx>, &'static str> {
let ret_type = self.context.f64_type();
let args_types = std::iter::repeat(ret_type)
.take(proto.args.len())
Expand All @@ -1109,7 +1109,7 @@ impl<'a> Compiler<'a> {
}

/// Compiles the specified `Function` into an LLVM `FunctionValue`.
fn compile_fn(&mut self) -> Result<FunctionValue, &'static str> {
fn compile_fn(&mut self) -> Result<FunctionValue<'ctx>, &'static str> {
let proto = &self.function.prototype;
let function = self.compile_prototype(proto)?;

Expand All @@ -1118,7 +1118,7 @@ impl<'a> Compiler<'a> {
return Ok(function);
}

let entry = self.context.append_basic_block(&function, "entry");
let entry = self.context.append_basic_block(function, "entry");

self.builder.position_at_end(&entry);

Expand Down Expand Up @@ -1157,7 +1157,13 @@ impl<'a> Compiler<'a> {
}

/// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`.
pub fn compile(context: &'a Context, builder: &'a Builder, pass_manager: &'a PassManager<FunctionValue>, module: &'a Module, function: &Function) -> Result<FunctionValue, &'static str> {
pub fn compile(
context: &'ctx Context,
builder: &'a Builder<'ctx>,
pass_manager: &'a PassManager<FunctionValue<'ctx>>,
module: &'a Module<'ctx>,
function: &Function,
) -> Result<FunctionValue<'ctx>, &'static str> {
let mut compiler = Compiler {
context: context,
builder: builder,
Expand Down
77 changes: 23 additions & 54 deletions src/basic_block.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
//! A `BasicBlock` is a container of instructions.
use llvm_sys::core::{LLVMGetBasicBlockParent, LLVMGetBasicBlockTerminator, LLVMGetNextBasicBlock, LLVMInsertBasicBlock, LLVMIsABasicBlock, LLVMIsConstant, LLVMMoveBasicBlockAfter, LLVMMoveBasicBlockBefore, LLVMPrintTypeToString, LLVMPrintValueToString, LLVMTypeOf, LLVMDeleteBasicBlock, LLVMGetPreviousBasicBlock, LLVMRemoveBasicBlockFromParent, LLVMGetFirstInstruction, LLVMGetLastInstruction, LLVMGetTypeContext, LLVMBasicBlockAsValue};
use llvm_sys::core::{LLVMGetBasicBlockParent, LLVMGetBasicBlockTerminator, LLVMGetNextBasicBlock, LLVMIsABasicBlock, LLVMIsConstant, LLVMMoveBasicBlockAfter, LLVMMoveBasicBlockBefore, LLVMPrintTypeToString, LLVMPrintValueToString, LLVMTypeOf, LLVMDeleteBasicBlock, LLVMGetPreviousBasicBlock, LLVMRemoveBasicBlockFromParent, LLVMGetFirstInstruction, LLVMGetLastInstruction, LLVMGetTypeContext, LLVMBasicBlockAsValue};
#[llvm_versions(3.9..=latest)]
use llvm_sys::core::LLVMGetBasicBlockName;
use llvm_sys::prelude::{LLVMValueRef, LLVMBasicBlockRef};

use crate::context::{Context, ContextRef};
use crate::context::ContextRef;
use crate::values::{FunctionValue, InstructionValue};

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

/// A `BasicBlock` is a container of instructions.
///
Expand Down Expand Up @@ -52,7 +51,7 @@ impl BasicBlock {
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// assert_eq!(basic_block.get_parent().unwrap(), function);
///
Expand Down Expand Up @@ -82,14 +81,14 @@ impl BasicBlock {
/// let fn_type = void_type.fn_type(&[], false);
/// let function1 = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block1 = context.append_basic_block(&function1, "entry");
/// let basic_block1 = context.append_basic_block(function1, "entry");
///
/// assert!(basic_block1.get_previous_basic_block().is_none());
///
/// let function2 = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block2 = context.append_basic_block(&function2, "entry");
/// let basic_block3 = context.append_basic_block(&function2, "next");
/// let basic_block2 = context.append_basic_block(function2, "entry");
/// let basic_block3 = context.append_basic_block(function2, "next");
///
/// assert!(basic_block2.get_previous_basic_block().is_none());
/// assert_eq!(basic_block3.get_previous_basic_block().unwrap(), basic_block2);
Expand Down Expand Up @@ -120,14 +119,14 @@ impl BasicBlock {
/// let fn_type = void_type.fn_type(&[], false);
/// let function1 = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block1 = context.append_basic_block(&function1, "entry");
/// let basic_block1 = context.append_basic_block(function1, "entry");
///
/// assert!(basic_block1.get_next_basic_block().is_none());
///
/// let function2 = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block2 = context.append_basic_block(&function2, "entry");
/// let basic_block3 = context.append_basic_block(&function2, "next");
/// let basic_block2 = context.append_basic_block(function2, "entry");
/// let basic_block3 = context.append_basic_block(function2, "next");
///
/// assert!(basic_block1.get_next_basic_block().is_none());
/// assert_eq!(basic_block2.get_next_basic_block().unwrap(), basic_block3);
Expand Down Expand Up @@ -160,8 +159,8 @@ impl BasicBlock {
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block1 = context.append_basic_block(&function, "entry");
/// let basic_block2 = context.append_basic_block(&function, "next");
/// let basic_block1 = context.append_basic_block(function, "entry");
/// let basic_block2 = context.append_basic_block(function, "next");
///
/// basic_block2.move_before(&basic_block1);
///
Expand Down Expand Up @@ -197,8 +196,8 @@ impl BasicBlock {
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block1 = context.append_basic_block(&function, "entry");
/// let basic_block2 = context.append_basic_block(&function, "next");
/// let basic_block1 = context.append_basic_block(function, "entry");
/// let basic_block2 = context.append_basic_block(function, "next");
///
/// basic_block1.move_after(&basic_block2);
///
Expand All @@ -219,36 +218,6 @@ impl BasicBlock {
Ok(())
}

/// Prepends a new `BasicBlock` before this one.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::module::Module;
/// use inkwell::builder::Builder;
///
/// let context = Context::create();
/// let module = context.create_module("my_module");
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
///
/// let basic_block1 = context.append_basic_block(&function, "entry");
/// let basic_block2 = basic_block1.prepend_basic_block("previous");
///
/// assert!(basic_block1.get_next_basic_block().is_none());
/// assert_eq!(basic_block2.get_next_basic_block().unwrap(), basic_block1);
/// ```
pub fn prepend_basic_block(&self, name: &str) -> BasicBlock {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let bb = unsafe {
LLVMInsertBasicBlock(self.basic_block, c_string.as_ptr())
};

BasicBlock::new(bb).expect("Prepending basic block should never fail")
}

/// Obtains the first `InstructionValue` in this `BasicBlock`, if any.
///
/// # Example
Expand All @@ -264,7 +233,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// builder.position_at_end(&basic_block);
/// builder.build_return(None);
Expand Down Expand Up @@ -298,7 +267,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// builder.position_at_end(&basic_block);
/// builder.build_return(None);
Expand Down Expand Up @@ -332,7 +301,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// builder.position_at_end(&basic_block);
/// builder.build_return(None);
Expand Down Expand Up @@ -369,7 +338,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// assert_eq!(basic_block.get_parent().unwrap(), function);
///
Expand Down Expand Up @@ -408,7 +377,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// unsafe {
/// basic_block.delete();
Expand Down Expand Up @@ -439,17 +408,17 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let function = module.add_function("do_nothing", fn_type, None);
/// let basic_block = context.append_basic_block(&function, "entry");
/// let basic_block = context.append_basic_block(function, "entry");
///
/// assert_eq!(context, *basic_block.get_context());
/// ```
// FIXME: Needs 'ctx on BB lifetime to work correctly
pub fn get_context(&self) -> ContextRef {
let context = unsafe {
LLVMGetTypeContext(LLVMTypeOf(LLVMBasicBlockAsValue(self.basic_block)))
};

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

/// Gets the name of a `BasicBlock`.
Expand All @@ -466,7 +435,7 @@ impl BasicBlock {
/// let void_type = context.void_type();
/// let fn_type = void_type.fn_type(&[], false);
/// let fn_val = module.add_function("my_fn", fn_type, None);
/// let bb = context.append_basic_block(&fn_val, "entry");
/// let bb = context.append_basic_block(fn_val, "entry");
///
/// assert_eq!(*bb.get_name(), *CString::new("entry").unwrap());
/// ```
Expand Down
Loading

0 comments on commit 4aeb597

Please sign in to comment.