From 4f6dd49df3f19204694fcea55f38efd9c5118bf2 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 4 Oct 2021 22:51:42 +0200 Subject: ch5: added if/then/else --- src/llvm/basic_block.rs | 39 ++++++++++++++++++++ src/llvm/builder.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++-- src/llvm/mod.rs | 8 +--- src/llvm/module.rs | 22 +++++++++-- src/llvm/value.rs | 13 ++++++- 5 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 src/llvm/basic_block.rs (limited to 'src/llvm') 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 { -- cgit v1.2.3