Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods for creating/checking for poison values. #431

Merged
merged 4 commits into from
Aug 25, 2023
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
19 changes: 19 additions & 0 deletions src/types/array_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,25 @@ impl<'ctx> ArrayType<'ctx> {
unsafe { ArrayValue::new(self.array_type.get_undef()) }
}

/// Creates a poison instance of a `ArrayType`.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::values::AnyValue;
///
/// let context = Context::create();
/// let i8_type = context.i8_type();
/// let i8_array_type = i8_type.array_type(3);
/// let i8_array_poison = i8_array_type.get_poison();
///
/// assert!(i8_array_poison.is_poison());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(self) -> ArrayValue<'ctx> {
unsafe { ArrayValue::new(self.array_type.get_poison()) }
}

// SubType: ArrayType<BT> -> BT?
/// Gets the element type of this `ArrayType`.
///
Expand Down
18 changes: 18 additions & 0 deletions src/types/float_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,24 @@ impl<'ctx> FloatType<'ctx> {
unsafe { FloatValue::new(self.float_type.get_undef()) }
}

/// Creates a poison instance of a `FloatType`.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::values::AnyValue;
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
/// let f32_poison = f32_type.get_poison();
///
/// assert!(f32_poison.is_poison());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(&self) -> FloatValue<'ctx> {
unsafe { FloatValue::new(self.float_type.get_poison()) }
}

/// Creates a `GenericValue` for use with `ExecutionEngine`s.
pub fn create_generic_value(self, value: f64) -> GenericValue<'ctx> {
unsafe { GenericValue::new(LLVMCreateGenericValueOfFloat(self.as_type_ref(), value)) }
Expand Down
19 changes: 19 additions & 0 deletions src/types/int_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,25 @@ impl<'ctx> IntType<'ctx> {
unsafe { IntValue::new(self.int_type.get_undef()) }
}

/// Creates a poison instance of an `IntType`.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::AddressSpace;
/// use inkwell::values::AnyValue;
///
/// let context = Context::create();
/// let i8_type = context.i8_type();
/// let i8_poison = i8_type.get_poison();
///
/// assert!(i8_poison.is_poison());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(self) -> IntValue<'ctx> {
unsafe { IntValue::new(self.int_type.get_poison()) }
}

/// Creates a `GenericValue` for use with `ExecutionEngine`s.
pub fn create_generic_value(self, value: u64, is_signed: bool) -> GenericValue<'ctx> {
unsafe { GenericValue::new(LLVMCreateGenericValueOfInt(self.as_type_ref(), value, is_signed as i32)) }
Expand Down
12 changes: 10 additions & 2 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ pub use crate::types::traits::{AnyType, AsTypeRef, BasicType, FloatMathType, Int
pub use crate::types::vec_type::VectorType;
pub use crate::types::void_type::VoidType;

#[llvm_versions(12.0..=latest)]
use llvm_sys::core::LLVMGetPoison;

use llvm_sys::core::{
LLVMAlignOf, LLVMArrayType, LLVMConstNull, LLVMConstPointerNull, LLVMFunctionType, LLVMGetElementType,
LLVMGetTypeContext, LLVMGetTypeKind, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString, LLVMSizeOf,
LLVMTypeIsSized, LLVMVectorType,
LLVMGetTypeContext, LLVMGetTypeKind, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString,
LLVMSizeOf, LLVMTypeIsSized, LLVMVectorType,
};
use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
use llvm_sys::LLVMTypeKind;
Expand Down Expand Up @@ -134,6 +137,11 @@ impl<'ctx> Type<'ctx> {
unsafe { LLVMGetUndef(self.ty) }
}

#[llvm_versions(12.0..=latest)]
fn get_poison(&self) -> LLVMValueRef {
unsafe { LLVMGetPoison(self.ty) }
}

fn get_alignment(self) -> IntValue<'ctx> {
unsafe { IntValue::new(LLVMAlignOf(self.ty)) }
}
Expand Down
20 changes: 20 additions & 0 deletions src/types/ptr_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,26 @@ impl<'ctx> PointerType<'ctx> {
unsafe { PointerValue::new(self.ptr_type.get_undef()) }
}

/// Creates a poison instance of a `PointerType`.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::AddressSpace;
/// use inkwell::values::AnyValue;
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
/// let f32_ptr_undef = f32_ptr_type.get_poison();
///
/// assert!(f32_ptr_undef.is_poison());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(self) -> PointerValue<'ctx> {
unsafe { PointerValue::new(self.ptr_type.get_poison()) }
}

/// Creates a `VectorType` with this `PointerType` for its element type.
///
/// # Example
Expand Down
21 changes: 21 additions & 0 deletions src/types/struct_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,27 @@ impl<'ctx> StructType<'ctx> {
unsafe { StructValue::new(self.struct_type.get_undef()) }
}

/// Creates a poison instance of a `StructType`.
///
/// # Example
///
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::values::AnyValue;
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
/// let i8_type = context.i8_type();
/// let struct_type = context.struct_type(&[f32_type.into(), i8_type.into()], false);
/// let struct_type_poison = struct_type.get_poison();
///
/// assert!(struct_type_poison.is_poison());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(self) -> StructValue<'ctx> {
unsafe { StructValue::new(self.struct_type.get_poison()) }
}

/// Defines the body of a `StructType`.
///
/// If the struct is an opaque type, it will no longer be after this call.
Expand Down
19 changes: 19 additions & 0 deletions src/types/vec_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,25 @@ impl<'ctx> VectorType<'ctx> {
unsafe { VectorValue::new(self.vec_type.get_undef()) }
}

/// Creates a poison instance of a `VectorType`.
///
/// # Example
/// ```no_run
/// use inkwell::context::Context;
/// use inkwell::AddressSpace;
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
/// let f32_vec_type = f32_type.vec_type(3);
/// let f32_vec_poison = f32_vec_type.get_undef();
///
/// assert!(f32_vec_poison.is_undef());
/// ```
#[llvm_versions(12.0..=latest)]
pub fn get_poison(self) -> VectorValue<'ctx> {
unsafe { VectorValue::new(self.vec_type.get_poison()) }
}

// SubType: VectorType<BT> -> BT?
/// Gets the element type of this `VectorType`.
///
Expand Down
7 changes: 5 additions & 2 deletions src/values/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ pub use crate::values::traits::AsValueRef;
pub use crate::values::traits::{AggregateValue, AnyValue, BasicValue, FloatMathValue, IntMathValue, PointerMathValue};
pub use crate::values::vec_value::VectorValue;

#[llvm_versions(12.0..=latest)]
use llvm_sys::core::LLVMIsPoison;

use llvm_sys::core::{
LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull, LLVMIsUndef,
LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection, LLVMTypeOf,
LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull,
LLVMIsUndef, LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection, LLVMTypeOf,
};
use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};

Expand Down
9 changes: 9 additions & 0 deletions src/values/traits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use llvm_sys::prelude::LLVMValueRef;

#[llvm_versions(12.0..=latest)]
use llvm_sys::core::LLVMIsPoison;

use std::fmt::Debug;

use crate::support::LLVMString;
Expand Down Expand Up @@ -144,6 +147,12 @@ pub unsafe trait AnyValue<'ctx>: AsValueRef + Debug {
fn print_to_string(&self) -> LLVMString {
unsafe { Value::new(self.as_value_ref()).print_to_string() }
}

/// Returns whether the value is `poison`
#[llvm_versions(12.0..=latest)]
fn is_poison(&self) -> bool {
unsafe { LLVMIsPoison(self.as_value_ref()) == 1 }
}
}

trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
Expand Down
37 changes: 37 additions & 0 deletions tests/all/test_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,43 @@ fn test_insert_value() {
assert!(module.verify().is_ok());
}

#[test]
fn test_insert_element() {
use inkwell::types::IntType;
use inkwell::values::VectorValue;

let context = Context::create();
let module = context.create_module("vec");

let fn_type = context.void_type().fn_type(&[], false);
let fn_value = module.add_function("vec_fn", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");

builder.position_at_end(entry);

#[llvm_versions(12.0..=latest)]
fn get_empty_vector_of(ty: IntType<'_>) -> VectorValue<'_> {
ty.vec_type(4).get_poison()
}
#[llvm_versions(4.0..12.0)]
fn get_empty_vector_of(ty: IntType<'_>) -> VectorValue<'_> {
ty.vec_type(4).get_undef()
}

let i8_ty = context.i8_type();
let i32_ty = context.i32_type();
let mut v = get_empty_vector_of(i8_ty);
v = builder.build_insert_element(v, i8_ty.const_int(0, false), i32_ty.const_int(0, false), "v0");
v = builder.build_insert_element(v, i8_ty.const_int(1, false), i32_ty.const_int(1, false), "v1");
v = builder.build_insert_element(v, i8_ty.const_int(2, false), i32_ty.const_int(2, false), "v2");
v = builder.build_insert_element(v, i8_ty.const_int(3, false), i32_ty.const_int(3, false), "v3");

builder.build_return(None);

assert!(module.verify().is_ok());
}

fn is_alignment_ok(align: u32) -> bool {
// This replicates the assertions LLVM runs.
//
Expand Down
84 changes: 84 additions & 0 deletions tests/all/test_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,90 @@ fn test_undef() {
assert!(ppc_f128_undef.is_undef());
}

#[llvm_versions(12.0..=latest)]
#[test]
fn test_poison() {
let context = Context::create();
let bool_type = context.bool_type();
let i8_type = context.i8_type();
let i16_type = context.i16_type();
let i32_type = context.i32_type();
let i64_type = context.i64_type();
let i128_type = context.i128_type();
let f16_type = context.f16_type();
let f32_type = context.f32_type();
let f64_type = context.f64_type();
let f128_type = context.f128_type();
let array_type = f64_type.array_type(42);
let ppc_f128_type = context.ppc_f128_type();

assert_eq!(array_type.get_element_type().into_float_type(), f64_type);

let bool_val = bool_type.const_int(0, false);
let i8_val = i8_type.const_int(0, false);
let i16_val = i16_type.const_int(0, false);
let i32_val = i32_type.const_int(0, false);
let i64_val = i64_type.const_int(0, false);
let i128_val = i128_type.const_int(0, false);
let f16_val = f16_type.const_float(0.0);
let f32_val = f32_type.const_float(0.0);
let f64_val = f64_type.const_float(0.0);
let f128_val = f128_type.const_float(0.0);
let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
let array_val = f64_type.const_array(&[f64_val]);
let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
let vec_val = VectorType::const_vector(&[i8_val]);
let ppc_f128_val = ppc_f128_type.const_float(0.0);

assert!(!bool_val.is_poison());
assert!(!i8_val.is_poison());
assert!(!i16_val.is_poison());
assert!(!i32_val.is_poison());
assert!(!i64_val.is_poison());
assert!(!i128_val.is_poison());
assert!(!f16_val.is_poison());
assert!(!f32_val.is_poison());
assert!(!f64_val.is_poison());
assert!(!f128_val.is_poison());
assert!(!ptr_val.is_poison());
assert!(!array_val.is_poison());
assert!(!struct_val.is_poison());
assert!(!vec_val.is_poison());
assert!(!ppc_f128_val.is_poison());

let bool_poison = bool_type.get_poison();
let i8_poison = i8_type.get_poison();
let i16_poison = i16_type.get_poison();
let i32_poison = i32_type.get_poison();
let i64_poison = i64_type.get_poison();
let i128_poison = i128_type.get_poison();
let f16_poison = f16_type.get_poison();
let f32_poison = f32_type.get_poison();
let f64_poison = f64_type.get_poison();
let f128_poison = f128_type.get_poison();
let ptr_poison = bool_type.ptr_type(AddressSpace::default()).get_poison();
let array_poison = array_type.get_poison();
let struct_poison = context.struct_type(&[bool_type.into()], false).get_poison();
let vec_poison = bool_type.vec_type(1).get_poison();
let ppc_f128_poison = ppc_f128_type.get_poison();

assert!(bool_poison.is_poison());
assert!(i8_poison.is_poison());
assert!(i16_poison.is_poison());
assert!(i32_poison.is_poison());
assert!(i64_poison.is_poison());
assert!(i128_poison.is_poison());
assert!(f16_poison.is_poison());
assert!(f32_poison.is_poison());
assert!(f64_poison.is_poison());
assert!(f128_poison.is_poison());
assert!(ptr_poison.is_poison());
assert!(array_poison.is_poison());
assert!(struct_poison.is_poison());
assert!(vec_poison.is_poison());
assert!(ppc_f128_poison.is_poison());
}

#[test]
fn test_consecutive_fns() {
let context = Context::create();
Expand Down