Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ llvm-sys-181 = { package = "llvm-sys", version = "181.2.0", optional = true }
llvm-sys-191 = { package = "llvm-sys", version = "191.0.0", optional = true }
llvm-sys-201 = { package = "llvm-sys", version = "201.0.0", optional = true }

either = "1.5"
libc = "0.2"
once_cell = "1.16"
thiserror = "2.0.11"
Expand Down
4 changes: 2 additions & 2 deletions examples/kaleidoscope/implementation_typed_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
.build_call(fun, &[lhs.into(), rhs.into()], "tmpbin")
.unwrap()
.try_as_basic_value()
.left()
.basic()
{
Some(value) => Ok(value.into_float_value()),
None => Err("Invalid call produced."),
Expand Down Expand Up @@ -1001,7 +1001,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
.build_call(fun, argsv.as_slice(), "tmp")
.unwrap()
.try_as_basic_value()
.left()
.basic()
{
Some(value) => Ok(value.into_float_value()),
None => Err("Invalid call produced."),
Expand Down
2 changes: 1 addition & 1 deletion src/basic_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ impl<'ctx> BasicBlock<'ctx> {
///
/// bb1.replace_all_uses_with(&bb2);
///
/// assert_eq!(branch_inst.get_operand(0).unwrap().right().unwrap(), bb2);
/// assert_eq!(branch_inst.get_operand(0).unwrap().unwrap_block(), bb2);
/// ```
pub fn replace_all_uses_with(self, other: &BasicBlock<'ctx>) {
let value = unsafe { LLVMBasicBlockAsValue(self.basic_block) };
Expand Down
17 changes: 7 additions & 10 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,7 @@ impl<'ctx> Builder<'ctx> {
///
/// let ret_val = builder.build_call(fn_value, &[i32_arg.into(), md_string.into()], "call").unwrap()
/// .try_as_basic_value()
/// .left()
/// .unwrap();
/// .unwrap_basic();
///
/// builder.build_return(Some(&ret_val)).unwrap();
/// ```
Expand Down Expand Up @@ -320,8 +319,7 @@ impl<'ctx> Builder<'ctx> {
///
/// let ret_val = builder.build_call(fn_value, &[i32_arg.into(), md_string.into()], "call").unwrap()
/// .try_as_basic_value()
/// .left()
/// .unwrap();
/// .unwrap_basic();
///
/// builder.build_return(Some(&ret_val)).unwrap();
/// ```
Expand Down Expand Up @@ -367,7 +365,7 @@ impl<'ctx> Builder<'ctx> {
/// )
/// .unwrap()
/// .try_as_basic_value()
/// .unwrap_left();
/// .unwrap_basic();
/// builder.build_return(Some(&ret_val)).unwrap();
///
/// # module.verify().unwrap();
Expand Down Expand Up @@ -413,8 +411,7 @@ impl<'ctx> Builder<'ctx> {
/// let function_pointer = fn_value.as_global_value().as_pointer_value();
/// let ret_val = builder.build_indirect_call(fn_value.get_type(), function_pointer, &[i32_arg.into(), md_string.into()], "call").unwrap()
/// .try_as_basic_value()
/// .left()
/// .unwrap();
/// .unwrap_basic();
///
/// builder.build_return(Some(&ret_val)).unwrap();
/// ```
Expand Down Expand Up @@ -585,7 +582,7 @@ impl<'ctx> Builder<'ctx> {
/// builder.position_at_end(then_block);
///
/// // in the then_block, the `call_site` value is defined and can be used
/// let result = call_site.try_as_basic_value().left().unwrap();
/// let result = call_site.try_as_basic_value().unwrap_basic();
///
/// builder.build_return(Some(&result)).unwrap();
/// }
Expand Down Expand Up @@ -707,7 +704,7 @@ impl<'ctx> Builder<'ctx> {
/// builder.position_at_end(then_block);
///
/// // in the then_block, the `call_site` value is defined and can be used
/// let result = call_site.try_as_basic_value().left().unwrap();
/// let result = call_site.try_as_basic_value().unwrap_basic();
///
/// builder.build_return(Some(&result)).unwrap();
/// }
Expand Down Expand Up @@ -1068,7 +1065,7 @@ impl<'ctx> Builder<'ctx> {
/// builder.position_at_end(then_block);
///
/// // in the then_block, the `call_site` value is defined and can be used
/// let result = call_site.try_as_basic_value().left().unwrap();
/// let result = call_site.try_as_basic_value().unwrap_basic();
///
/// builder.build_return(Some(&result)).unwrap();
/// }
Expand Down
2 changes: 1 addition & 1 deletion src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'ctx> ExecutionEngine<'ctx> {
///
/// let argf = ft.const_float(64.);
/// let call_site_value = builder.build_call(extf, &[argf.into(), argf.into()], "retv").unwrap();
/// let retv = call_site_value.try_as_basic_value().left().unwrap().into_float_value();
/// let retv = call_site_value.try_as_basic_value().unwrap_basic().into_float_value();
///
/// builder.build_return(Some(&retv)).unwrap();
///
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ use llvm_sys::{

use llvm_sys::LLVMInlineAsmDialect;

pub use either::Either;
pub use error::Error;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
Expand Down
95 changes: 86 additions & 9 deletions src/values/basic_value_use.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
use either::{
Either,
Either::{Left, Right},
};
use llvm_sys::core::{LLVMGetNextUse, LLVMGetUsedValue, LLVMGetUser, LLVMIsABasicBlock, LLVMValueAsBasicBlock};
use llvm_sys::prelude::LLVMUseRef;

Expand All @@ -10,6 +6,87 @@ use std::marker::PhantomData;
use crate::basic_block::BasicBlock;
use crate::values::{AnyValueEnum, BasicValueEnum};

/// Either [BasicValueEnum] or [BasicBlock].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Operand<'ctx> {
Value(BasicValueEnum<'ctx>),
Block(BasicBlock<'ctx>),
}

impl<'ctx> Operand<'ctx> {
/// Determines if the [Operand] is a [BasicValueEnum].
#[inline]
#[must_use]
pub fn is_value(self) -> bool {
matches!(self, Self::Value(_))
}

/// Determines if the [Operand] is a [BasicBlock].
#[inline]
#[must_use]
pub fn is_block(self) -> bool {
matches!(self, Self::Block(_))
}

/// If the [Operand] is a [BasicValueEnum], map it into [Option::Some].
#[inline]
#[must_use]
pub fn value(self) -> Option<BasicValueEnum<'ctx>> {
match self {
Self::Value(value) => Some(value),
_ => None,
}
}

/// If the [Operand] is a [BasicBlock], map it into [Option::Some].
#[inline]
#[must_use]
pub fn block(self) -> Option<BasicBlock<'ctx>> {
match self {
Self::Block(block) => Some(block),
_ => None,
}
}

/// Expect [BasicValueEnum], panic with the message if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn expect_value(self, msg: &str) -> BasicValueEnum<'ctx> {
match self {
Self::Value(value) => value,
_ => panic!("{msg}"),
}
}

/// Expect [BasicBlock], panic with the message if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn expect_block(self, msg: &str) -> BasicBlock<'ctx> {
match self {
Self::Block(block) => block,
_ => panic!("{msg}"),
}
}

/// Unwrap [BasicValueEnum]. Will panic if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn unwrap_value(self) -> BasicValueEnum<'ctx> {
self.expect_value("Called unwrap_value() on UsedValue::Block.")
}

/// Unwrap [BasicBlock]. Will panic if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn unwrap_block(self) -> BasicBlock<'ctx> {
self.expect_block("Called unwrap_block() on UsedValue::Value.")
}
}

/// A usage of a `BasicValue` in another value.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BasicValueUse<'ctx>(LLVMUseRef, PhantomData<&'ctx ()>);
Expand Down Expand Up @@ -160,28 +237,28 @@ impl<'ctx> BasicValueUse<'ctx> {
/// let free_instruction = builder.build_free(arg1).unwrap();
/// let return_instruction = builder.build_return(None).unwrap();
///
/// let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
/// let free_operand0 = free_instruction.get_operand(0).unwrap().unwrap_value();
/// let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();
/// let bitcast_use_value = free_operand0_instruction
/// .get_first_use()
/// .unwrap()
/// .get_used_value()
/// .left()
/// .value()
/// .unwrap();
///
/// assert_eq!(bitcast_use_value, free_operand0);
/// ```
pub fn get_used_value(self) -> Either<BasicValueEnum<'ctx>, BasicBlock<'ctx>> {
pub fn get_used_value(self) -> Operand<'ctx> {
let used_value = unsafe { LLVMGetUsedValue(self.0) };

let is_basic_block = unsafe { !LLVMIsABasicBlock(used_value).is_null() };

if is_basic_block {
let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(used_value)) };

Right(bb.expect("BasicBlock should always be valid"))
Operand::Block(bb.expect("BasicBlock should always be valid"))
} else {
unsafe { Left(BasicValueEnum::new(used_value)) }
unsafe { Operand::Value(BasicValueEnum::new(used_value)) }
}
}
}
91 changes: 85 additions & 6 deletions src/values/call_site_value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::fmt::{self, Display};

use either::Either;

use llvm_sys::core::LLVMGetCalledFunctionType;
use llvm_sys::core::{
LLVMGetCalledValue, LLVMGetInstructionCallConv, LLVMGetTypeKind, LLVMIsTailCall, LLVMSetInstrParamAlignment,
Expand All @@ -20,6 +18,87 @@ use crate::values::{AsValueRef, BasicValueEnum, FunctionValue, InstructionValue,

use super::{AnyValue, InstructionOpcode};

/// Either [BasicValueEnum] or [InstructionValue].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValueKind<'ctx> {
Basic(BasicValueEnum<'ctx>),
Instruction(InstructionValue<'ctx>),
}

impl<'ctx> ValueKind<'ctx> {
/// Determines if the [ValueKind] is a [BasicValueEnum].
#[inline]
#[must_use]
pub fn is_basic(self) -> bool {
matches!(self, Self::Basic(_))
}

/// Determines if the [ValueKind] is an [InstructionValue].
#[inline]
#[must_use]
pub fn is_instruction(self) -> bool {
matches!(self, Self::Instruction(_))
}

/// If the [ValueKind] is a [BasicValueEnum], map it into [Option::Some].
#[inline]
#[must_use]
pub fn basic(self) -> Option<BasicValueEnum<'ctx>> {
match self {
Self::Basic(value) => Some(value),
_ => None,
}
}

/// If the [ValueKind] is an [InstructionValue], map it into [Option::Some].
#[inline]
#[must_use]
pub fn instruction(self) -> Option<InstructionValue<'ctx>> {
match self {
Self::Instruction(inst) => Some(inst),
_ => None,
}
}

/// Expect [BasicValueEnum], panic with the message if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn expect_basic(self, msg: &str) -> BasicValueEnum<'ctx> {
match self {
Self::Basic(value) => value,
_ => panic!("{msg}"),
}
}

/// Expect [InstructionValue], panic with the message if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn expect_instruction(self, msg: &str) -> InstructionValue<'ctx> {
match self {
Self::Instruction(inst) => inst,
_ => panic!("{msg}"),
}
}

/// Unwrap [BasicValueEnum]. Will panic if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn unwrap_basic(self) -> BasicValueEnum<'ctx> {
self.expect_basic("Called unwrap_basic() on ValueKind::Instruction.")
}

/// Unwrap [InstructionValue]. Will panic if it is not.
#[inline]
#[must_use]
#[track_caller]
pub fn unwrap_instruction(self) -> InstructionValue<'ctx> {
self.expect_instruction("Called unwrap_instruction() on ValueKind::Basic.")
}
}

/// A value resulting from a function call. It may have function attributes applied to it.
///
/// This struct may be removed in the future in favor of an `InstructionValue<CallSite>` type.
Expand Down Expand Up @@ -160,13 +239,13 @@ impl<'ctx> CallSiteValue<'ctx> {
///
/// let call_site_value = builder.build_call(fn_value, &[], "my_fn").unwrap();
///
/// assert!(call_site_value.try_as_basic_value().is_right());
/// assert!(call_site_value.try_as_basic_value().is_instruction());
/// ```
pub fn try_as_basic_value(self) -> Either<BasicValueEnum<'ctx>, InstructionValue<'ctx>> {
pub fn try_as_basic_value(self) -> ValueKind<'ctx> {
unsafe {
match LLVMGetTypeKind(LLVMTypeOf(self.as_value_ref())) {
LLVMTypeKind::LLVMVoidTypeKind => Either::Right(InstructionValue::new(self.as_value_ref())),
_ => Either::Left(BasicValueEnum::new(self.as_value_ref())),
LLVMTypeKind::LLVMVoidTypeKind => ValueKind::Instruction(InstructionValue::new(self.as_value_ref())),
_ => ValueKind::Basic(BasicValueEnum::new(self.as_value_ref())),
}
}
}
Expand Down
Loading
Loading