From 21ea78e57fa480d472d3660881e91813f7b18820 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sun, 27 Mar 2022 22:20:06 +0200 Subject: ch5: added for loop --- src/llvm/builder.rs | 16 ++++++------ src/llvm/mod.rs | 2 +- src/llvm/value.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 15 deletions(-) (limited to 'src/llvm') diff --git a/src/llvm/builder.rs b/src/llvm/builder.rs index 8f581f9..da10231 100644 --- a/src/llvm/builder.rs +++ b/src/llvm/builder.rs @@ -10,7 +10,7 @@ use llvm_sys::{ use std::marker::PhantomData; -use super::{BasicBlock, FnValue, Module, Type, Value}; +use super::{BasicBlock, FnValue, Module, PhiValue, Type, Value}; // Definition of LLVM C API functions using our `repr(transparent)` types. extern "C" { @@ -131,8 +131,8 @@ impl<'llvm> IRBuilder<'llvm> { /// /// Panics if LLVM API returns a `null` pointer. pub fn fcmpult(&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!"); + debug_assert!(lhs.is_f64(), "fcmpult: Expected f64 as lhs operand!"); + debug_assert!(rhs.is_f64(), "fcmpult: Expected f64 as rhs operand!"); let value_ref = unsafe { LLVMBuildFCmp( @@ -140,7 +140,7 @@ impl<'llvm> IRBuilder<'llvm> { LLVMRealPredicate::LLVMRealULT, lhs.value_ref(), rhs.value_ref(), - b"fcmplt\0".as_ptr().cast(), + b"fcmpult\0".as_ptr().cast(), ) }; Value::new(value_ref) @@ -152,8 +152,8 @@ impl<'llvm> IRBuilder<'llvm> { /// /// 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!"); + debug_assert!(lhs.is_f64(), "fcmone: Expected f64 as lhs operand!"); + debug_assert!(rhs.is_f64(), "fcmone: Expected f64 as rhs operand!"); let value_ref = unsafe { LLVMBuildFCmp( @@ -251,7 +251,7 @@ impl<'llvm> IRBuilder<'llvm> { &self, phi_type: Type<'llvm>, incoming: &[(Value<'llvm>, BasicBlock<'llvm>)], - ) -> Value<'llvm> { + ) -> PhiValue<'llvm> { let phi_ref = unsafe { LLVMBuildPhi(self.builder, phi_type.type_ref(), b"phi\0".as_ptr().cast()) }; assert!(!phi_ref.is_null()); @@ -268,7 +268,7 @@ impl<'llvm> IRBuilder<'llvm> { } } - Value::new(phi_ref) + PhiValue::new(phi_ref) } } diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index c9f17b6..1eb9c57 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -33,7 +33,7 @@ pub use lljit::{LLJit, ResourceTracker}; pub use module::Module; pub use pass_manager::FunctionPassManager; pub use type_::Type; -pub use value::{FnValue, Value}; +pub use value::{FnValue, PhiValue, Value}; struct Error<'llvm>(&'llvm mut libc::c_char); diff --git a/src/llvm/value.rs b/src/llvm/value.rs index 219c855..912c14e 100644 --- a/src/llvm/value.rs +++ b/src/llvm/value.rs @@ -1,9 +1,11 @@ +#![allow(unused)] + use llvm_sys::{ analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction}, core::{ - LLVMAppendExistingBasicBlock, LLVMCountBasicBlocks, LLVMCountParams, LLVMDumpValue, - LLVMGetParam, LLVMGetReturnType, LLVMGetValueKind, LLVMGetValueName2, LLVMSetValueName2, - LLVMTypeOf, + LLVMAddIncoming, LLVMAppendExistingBasicBlock, LLVMCountBasicBlocks, LLVMCountParams, + LLVMDumpValue, LLVMGetParam, LLVMGetReturnType, LLVMGetValueKind, LLVMGetValueName2, + LLVMIsAFunction, LLVMIsAPHINode, LLVMSetValueName2, LLVMTypeOf, }, prelude::LLVMValueRef, LLVMTypeKind, LLVMValueKind, @@ -43,6 +45,18 @@ impl<'llvm> Value<'llvm> { unsafe { LLVMGetValueKind(self.value_ref()) } } + /// Check if value is `function` type. + pub(super) fn is_function(&self) -> bool { + let cast = unsafe { LLVMIsAFunction(self.value_ref()) }; + !cast.is_null() + } + + /// Check if value is `phinode` type. + pub(super) fn is_phinode(&self) -> bool { + let cast = unsafe { LLVMIsAPHINode(self.value_ref()) }; + !cast.is_null() + } + /// Dump the LLVM Value to stdout. pub fn dump(&self) { unsafe { LLVMDumpValue(self.value_ref()) }; @@ -117,9 +131,8 @@ impl<'llvm> FnValue<'llvm> { /// Panics if `value_ref` is a null pointer. pub(super) fn new(value_ref: LLVMValueRef) -> Self { let value = Value::new(value_ref); - debug_assert_eq!( - value.kind(), - LLVMValueKind::LLVMFunctionValueKind, + debug_assert!( + value.is_function(), "Expected a fn value when constructing FnValue!" ); @@ -175,3 +188,50 @@ impl<'llvm> FnValue<'llvm> { } } } + +/// Wrapper for a LLVM Value Reference specialized for contexts where phi values are needed. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct PhiValue<'llvm>(Value<'llvm>); + +impl<'llvm> Deref for PhiValue<'llvm> { + type Target = Value<'llvm>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'llvm> PhiValue<'llvm> { + /// Create a new PhiValue instance. + /// + /// # Panics + /// + /// Panics if `value_ref` is a null pointer. + pub(super) fn new(value_ref: LLVMValueRef) -> Self { + let value = Value::new(value_ref); + debug_assert!( + value.is_phinode(), + "Expected a phinode value when constructing PhiValue!" + ); + + PhiValue(value) + } + + /// Add an incoming value to the end of a PHI list. + pub fn add_incoming(&self, ival: Value<'llvm>, ibb: BasicBlock<'llvm>) { + debug_assert_eq!( + ival.type_of().kind(), + self.type_of().kind(), + "Type of incoming phi value must be the same as the type used to build the phi node." + ); + + unsafe { + LLVMAddIncoming( + self.value_ref(), + &mut ival.value_ref() as _, + &mut ibb.bb_ref() as _, + 1, + ); + } + } +} -- cgit v1.2.3