aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm')
-rw-r--r--src/llvm/basic_block.rs39
-rw-r--r--src/llvm/builder.rs98
-rw-r--r--src/llvm/mod.rs8
-rw-r--r--src/llvm/module.rs22
-rw-r--r--src/llvm/value.rs13
5 files changed, 164 insertions, 16 deletions
diff --git a/src/llvm/basic_block.rs b/src/llvm/basic_block.rs
new file mode 100644
index 0000000..e40c7f1
--- /dev/null
+++ b/src/llvm/basic_block.rs
@@ -0,0 +1,39 @@
+use llvm_sys::{core::LLVMGetBasicBlockParent, prelude::LLVMBasicBlockRef};
+
+use std::marker::PhantomData;
+
+use super::FnValue;
+
+/// Wrapper for a LLVM Basic Block.
+#[derive(Copy, Clone)]
+pub struct BasicBlock<'llvm>(LLVMBasicBlockRef, PhantomData<&'llvm ()>);
+
+impl<'llvm> BasicBlock<'llvm> {
+ /// Create a new BasicBlock instance.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `bb_ref` is a null pointer.
+ pub(super) fn new(bb_ref: LLVMBasicBlockRef) -> BasicBlock<'llvm> {
+ assert!(!bb_ref.is_null());
+ BasicBlock(bb_ref, PhantomData)
+ }
+
+ /// Get the raw LLVM value reference.
+ #[inline]
+ pub(super) fn bb_ref(&self) -> LLVMBasicBlockRef {
+ self.0
+ }
+
+ /// Get the function to which the basic block belongs.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn get_parent(&self) -> FnValue<'llvm> {
+ let value_ref = unsafe { LLVMGetBasicBlockParent(self.bb_ref()) };
+ assert!(!value_ref.is_null());
+
+ FnValue::new(value_ref)
+ }
+}
diff --git a/src/llvm/builder.rs b/src/llvm/builder.rs
index 3d43b68..8f581f9 100644
--- a/src/llvm/builder.rs
+++ b/src/llvm/builder.rs
@@ -1,7 +1,8 @@
use llvm_sys::{
core::{
- LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul, LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP,
- LLVMCreateBuilderInContext, LLVMDisposeBuilder, LLVMPositionBuilderAtEnd,
+ LLVMAddIncoming, LLVMBuildBr, LLVMBuildCondBr, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul,
+ LLVMBuildFSub, LLVMBuildPhi, LLVMBuildRet, LLVMBuildUIToFP, LLVMCreateBuilderInContext,
+ LLVMDisposeBuilder, LLVMGetInsertBlock, LLVMPositionBuilderAtEnd,
},
prelude::{LLVMBuilderRef, LLVMValueRef},
LLVMRealPredicate,
@@ -48,10 +49,22 @@ impl<'llvm> IRBuilder<'llvm> {
/// Position the IR Builder at the end of the given Basic Block.
pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
unsafe {
- LLVMPositionBuilderAtEnd(self.builder, bb.0);
+ LLVMPositionBuilderAtEnd(self.builder, bb.bb_ref());
}
}
+ /// Get the BasicBlock the IRBuilder currently inputs into.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn get_insert_block(&self) -> BasicBlock<'llvm> {
+ let bb_ref = unsafe { LLVMGetInsertBlock(self.builder) };
+ assert!(!bb_ref.is_null());
+
+ BasicBlock::new(bb_ref)
+ }
+
/// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
///
/// # Panics
@@ -112,7 +125,7 @@ impl<'llvm> IRBuilder<'llvm> {
Value::new(value_ref)
}
- /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
+ /// Emit a [fcmpult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
///
/// # Panics
///
@@ -133,6 +146,27 @@ impl<'llvm> IRBuilder<'llvm> {
Value::new(value_ref)
}
+ /// Emit a [fcmpone](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn fcmpone(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+ debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
+ debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");
+
+ let value_ref = unsafe {
+ LLVMBuildFCmp(
+ self.builder,
+ LLVMRealPredicate::LLVMRealONE,
+ lhs.value_ref(),
+ rhs.value_ref(),
+ b"fcmpone\0".as_ptr().cast(),
+ )
+ };
+ Value::new(value_ref)
+ }
+
/// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
///
/// # Panics
@@ -180,6 +214,62 @@ impl<'llvm> IRBuilder<'llvm> {
let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
assert!(!ret.is_null());
}
+
+ /// Emit an unconditional [br](https://llvm.org/docs/LangRef.html#br-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn br(&self, dest: BasicBlock<'llvm>) {
+ let br_ref = unsafe { LLVMBuildBr(self.builder, dest.bb_ref()) };
+ assert!(!br_ref.is_null());
+ }
+
+ /// Emit a conditional [br](https://llvm.org/docs/LangRef.html#br-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn cond_br(&self, cond: Value<'llvm>, then: BasicBlock<'llvm>, else_: BasicBlock<'llvm>) {
+ let br_ref = unsafe {
+ LLVMBuildCondBr(
+ self.builder,
+ cond.value_ref(),
+ then.bb_ref(),
+ else_.bb_ref(),
+ )
+ };
+ assert!(!br_ref.is_null());
+ }
+
+ /// Emit a [phi](https://llvm.org/docs/LangRef.html#phi-instruction) instruction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn phi(
+ &self,
+ phi_type: Type<'llvm>,
+ incoming: &[(Value<'llvm>, BasicBlock<'llvm>)],
+ ) -> Value<'llvm> {
+ let phi_ref =
+ unsafe { LLVMBuildPhi(self.builder, phi_type.type_ref(), b"phi\0".as_ptr().cast()) };
+ assert!(!phi_ref.is_null());
+
+ for (val, bb) in incoming {
+ debug_assert_eq!(
+ val.type_of().kind(),
+ phi_type.kind(),
+ "Type of incoming phi value must be the same as the type used to build the phi node."
+ );
+
+ unsafe {
+ LLVMAddIncoming(phi_ref, &mut val.value_ref() as _, &mut bb.bb_ref() as _, 1);
+ }
+ }
+
+ Value::new(phi_ref)
+ }
}
impl Drop for IRBuilder<'_> {
diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs
index 16e6bfd..c9f17b6 100644
--- a/src/llvm/mod.rs
+++ b/src/llvm/mod.rs
@@ -11,7 +11,6 @@
use llvm_sys::{
core::LLVMShutdown,
error::{LLVMDisposeErrorMessage, LLVMErrorRef, LLVMGetErrorMessage},
- prelude::LLVMBasicBlockRef,
target::{
LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter,
LLVM_InitializeNativeTarget,
@@ -19,8 +18,8 @@ use llvm_sys::{
};
use std::ffi::CStr;
-use std::marker::PhantomData;
+mod basic_block;
mod builder;
mod lljit;
mod module;
@@ -28,6 +27,7 @@ mod pass_manager;
mod type_;
mod value;
+pub use basic_block::BasicBlock;
pub use builder::IRBuilder;
pub use lljit::{LLJit, ResourceTracker};
pub use module::Module;
@@ -35,10 +35,6 @@ pub use pass_manager::FunctionPassManager;
pub use type_::Type;
pub use value::{FnValue, Value};
-/// Wrapper for a LLVM Basic Block.
-#[derive(Copy, Clone)]
-pub struct BasicBlock<'llvm>(LLVMBasicBlockRef, PhantomData<&'llvm ()>);
-
struct Error<'llvm>(&'llvm mut libc::c_char);
impl<'llvm> Error<'llvm> {
diff --git a/src/llvm/module.rs b/src/llvm/module.rs
index d737b8e..21d85f5 100644
--- a/src/llvm/module.rs
+++ b/src/llvm/module.rs
@@ -1,7 +1,8 @@
use llvm_sys::{
core::{
- LLVMAddFunction, LLVMAppendBasicBlockInContext, LLVMDisposeModule, LLVMDoubleTypeInContext,
- LLVMDumpModule, LLVMGetNamedFunction, LLVMModuleCreateWithNameInContext,
+ LLVMAddFunction, LLVMAppendBasicBlockInContext, LLVMCreateBasicBlockInContext,
+ LLVMDisposeModule, LLVMDoubleTypeInContext, LLVMDumpModule, LLVMGetNamedFunction,
+ LLVMModuleCreateWithNameInContext,
},
orc2::{
LLVMOrcCreateNewThreadSafeContext, LLVMOrcCreateNewThreadSafeModule,
@@ -13,7 +14,6 @@ use llvm_sys::{
};
use std::convert::TryFrom;
-use std::marker::PhantomData;
use super::{BasicBlock, FnValue, Type};
use crate::SmallCStr;
@@ -176,7 +176,21 @@ impl<'llvm> Module {
};
assert!(!block.is_null());
- BasicBlock(block, PhantomData)
+ BasicBlock::new(block)
+ }
+
+ /// Create a free-standing Basic Block without adding it to a function.
+ /// This can be added to a function at a later point in time with
+ /// [`FnValue::append_basic_block`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if LLVM API returns a `null` pointer.
+ pub fn create_basic_block(&self) -> BasicBlock<'llvm> {
+ let block = unsafe { LLVMCreateBasicBlockInContext(self.ctx, b"block\0".as_ptr().cast()) };
+ assert!(!block.is_null());
+
+ BasicBlock::new(block)
}
}
diff --git a/src/llvm/value.rs b/src/llvm/value.rs
index 9b79c69..219c855 100644
--- a/src/llvm/value.rs
+++ b/src/llvm/value.rs
@@ -1,8 +1,9 @@
use llvm_sys::{
analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction},
core::{
- LLVMCountBasicBlocks, LLVMCountParams, LLVMDumpValue, LLVMGetParam, LLVMGetReturnType,
- LLVMGetValueKind, LLVMGetValueName2, LLVMSetValueName2, LLVMTypeOf,
+ LLVMAppendExistingBasicBlock, LLVMCountBasicBlocks, LLVMCountParams, LLVMDumpValue,
+ LLVMGetParam, LLVMGetReturnType, LLVMGetValueKind, LLVMGetValueName2, LLVMSetValueName2,
+ LLVMTypeOf,
},
prelude::LLVMValueRef,
LLVMTypeKind, LLVMValueKind,
@@ -12,6 +13,7 @@ use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::Deref;
+use super::BasicBlock;
use super::Type;
/// Wrapper for a LLVM Value Reference.
@@ -156,6 +158,13 @@ impl<'llvm> FnValue<'llvm> {
unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
}
+ /// Append a Basic Block to the end of the function value.
+ pub fn append_basic_block(&self, bb: BasicBlock<'llvm>) {
+ unsafe {
+ LLVMAppendExistingBasicBlock(self.value_ref(), bb.bb_ref());
+ }
+ }
+
/// Verify that the given function is valid.
pub fn verify(&self) -> bool {
unsafe {