diff --git a/src/support/mod.rs b/src/support/mod.rs index 6a26eb8f0ab..8086b085b8d 100644 --- a/src/support/mod.rs +++ b/src/support/mod.rs @@ -35,6 +35,7 @@ impl LLVMString { /// Don't use this if it's not necessary. You likely need to allocate /// a CString as input and then LLVM will likely allocate their own string /// anyway. + #[allow(dead_code)] fn create(bytes: *const c_char) -> LLVMString { let ptr = unsafe { LLVMCreateMessage(bytes) diff --git a/src/types/array_type.rs b/src/types/array_type.rs index f335866b60e..fdc7b65cfd8 100644 --- a/src/types/array_type.rs +++ b/src/types/array_type.rs @@ -6,7 +6,7 @@ use context::ContextRef; use support::LLVMString; use types::traits::AsTypeRef; use types::{Type, BasicTypeEnum, PointerType, FunctionType}; -use values::{AsValueRef, BasicValue, ArrayValue, PointerValue, IntValue}; +use values::{AsValueRef, ArrayValue, PointerValue, IntValue}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct ArrayType { diff --git a/src/types/float_type.rs b/src/types/float_type.rs index adefc937239..8ccb5106459 100644 --- a/src/types/float_type.rs +++ b/src/types/float_type.rs @@ -1,3 +1,5 @@ +//! This module contains functions for working with `FloatType`s and generating types and values from them. + use llvm_sys::core::{LLVMConstReal, LLVMConstNull, LLVMHalfType, LLVMFloatType, LLVMDoubleType, LLVMFP128Type, LLVMPPCFP128Type, LLVMConstRealOfStringAndSize, LLVMX86FP80Type, LLVMConstArray}; use llvm_sys::execution_engine::LLVMCreateGenericValueOfFloat; use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; @@ -9,6 +11,7 @@ use types::traits::AsTypeRef; use types::{Type, PointerType, FunctionType, BasicTypeEnum, ArrayType, VectorType}; use values::{AsValueRef, ArrayValue, FloatValue, GenericValue, PointerValue, IntValue}; +/// A `FloatType` is the type of a floating point constant or variable. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct FloatType { float_type: Type, @@ -23,18 +26,74 @@ impl FloatType { } } + /// Creates a `FunctionType` with this `FloatType` for its return type. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let fn_type = f32_type.fn_type(&[], false); + /// ``` pub fn fn_type(&self, param_types: &[BasicTypeEnum], is_var_args: bool) -> FunctionType { self.float_type.fn_type(param_types, is_var_args) } + /// Creates an `ArrayType` with this `FloatType` for its element type. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_array_type = f32_type.array_type(3); + /// + /// assert_eq!(f32_array_type.len(), 3); + /// assert_eq!(f32_array_type.get_element_type().into_float_type(), f32_type); + /// ``` pub fn array_type(&self, size: u32) -> ArrayType { self.float_type.array_type(size) } + /// Creates a `VectorType` with this `FloatType` for its element type. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_vector_type = f32_type.vec_type(3); + /// + /// assert_eq!(f32_vector_type.get_size(), 3); + /// assert_eq!(f32_vector_type.get_element_type().into_float_type(), f32_type); + /// ``` pub fn vec_type(&self, size: u32) -> VectorType { self.float_type.vec_type(size) } + /// Creates a `FloatValue` repesenting a constant value of this `FloatType`. + /// It will be automatically assigned this `FloatType`'s `Context`. + /// + /// # Example + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::types::FloatType; + /// + /// // Global Context + /// let f32_type = FloatType::f32_type(); + /// let f32_value = f32_type.const_float(42.); + /// + /// // Custom Context + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_value = f32_type.const_float(42.); + /// ``` pub fn const_float(&self, value: f64) -> FloatValue { let value = unsafe { LLVMConstReal(self.float_type.type_, value) @@ -43,7 +102,36 @@ impl FloatType { FloatValue::new(value) } - // REVIEW: What happens when string is invalid? Nullptr? + /// Create a `FloatValue` from a string. LLVM provides no error handling here, + /// so this may produce unexpected results and should not be relied upon for validation. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f64_type = context.f64_type(); + /// let f64_val = f64_type.const_float_from_string("3.6"); + /// + /// assert_eq!(f64_val.print_to_string().to_string(), "double 3.600000e+00"); + /// + /// let f64_val = f64_type.const_float_from_string("3."); + /// + /// assert_eq!(f64_val.print_to_string().to_string(), "double 3.000000e+00"); + /// + /// let f64_val = f64_type.const_float_from_string("3"); + /// + /// assert_eq!(f64_val.print_to_string().to_string(), "double 3.000000e+00"); + /// + /// let f64_val = f64_type.const_float_from_string(""); + /// + /// assert_eq!(f64_val.print_to_string().to_string(), "double 0.000000e+00"); + /// + /// let f64_val = f64_type.const_float_from_string("3.asd"); + /// + /// assert_eq!(f64_val.print_to_string().to_string(), "double 0x7FF0000000000000"); + /// ``` pub fn const_float_from_string(&self, slice: &str) -> FloatValue { let value = unsafe { LLVMConstRealOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32) @@ -52,10 +140,41 @@ impl FloatType { FloatValue::new(value) } + /// Creates a `PointerValue` representing a constant value of zero (null pointer) pointing to this `FloatType`. + /// It will be automatically assigned this `FloatType`'s `Context`. + /// + /// # Example + /// ``` + /// use inkwell::context::Context; + /// use inkwell::types::FloatType; + /// + /// // Global Context + /// let f32_type = FloatType::f32_type(); + /// let f32_value = f32_type.const_null_ptr(); + /// + /// // Custom Context + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_value = f32_type.const_null_ptr(); + /// ``` pub fn const_null_ptr(&self) -> PointerValue { self.float_type.const_null_ptr() } + /// Creates a constant null (zero) value of this `FloatType`. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_zero = f32_type.const_null(); + /// + /// assert!(f32_zero.is_null()); + /// assert_eq!(f32_zero.print_to_string().to_string(), "f32 0"); + /// ``` pub fn const_null(&self) -> FloatValue { let null = unsafe { LLVMConstNull(self.as_type_ref()) @@ -65,22 +184,83 @@ impl FloatType { } // REVIEW: Always true -> const fn? + /// Gets whether or not this `FloatType` is sized or not. This is likely + /// always true and may be removed in the future. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// + /// assert!(f32_type.is_sized()); + /// ``` pub fn is_sized(&self) -> bool { self.float_type.is_sized() } + /// Gets the size of this `FloatType`. Value may vary depending on the target architecture. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_type_size = f32_type.size_of(); + /// ``` pub fn size_of(&self) -> IntValue { self.float_type.size_of() } + /// Gets the aligment of this `FloatType`. Value may vary depending on the target architecture. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_type_alignment = f32_type.get_alignment(); + /// ``` pub fn get_alignment(&self) -> IntValue { self.float_type.get_alignment() } + /// Gets a reference to the `Context` this `FloatType` was created in. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// + /// assert_eq!(*f32_type.get_context(), context); + /// ``` pub fn get_context(&self) -> ContextRef { self.float_type.get_context() } + /// Creates a `PointerType` with this `FloatType` for its element type. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::AddressSpace; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// + /// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type); + /// ``` pub fn ptr_type(&self, address_space: AddressSpace) -> PointerType { self.float_type.ptr_type(address_space) } @@ -207,20 +387,36 @@ impl FloatType { FloatType::new(float_type) } + /// Prints the definition of a `FloatType` to a `LLVMString`. pub fn print_to_string(&self) -> LLVMString { self.float_type.print_to_string() } // See Type::print_to_stderr note on 5.0+ status + /// Prints the definition of an `IntType` to stderr. Not available in newer LLVM versions. #[cfg(any(feature = "llvm3-7", feature = "llvm3-8", feature = "llvm3-9", feature = "llvm4-0"))] pub fn print_to_stderr(&self) { self.float_type.print_to_stderr() } + /// Creates an undefined instance of an `FloatType`. + /// + /// # Example + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::AddressSpace; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_undef = f32_type.get_undef(); + /// + /// assert!(f32_undef.is_undef()); + /// ``` pub fn get_undef(&self) -> FloatValue { FloatValue::new(self.float_type.get_undef()) } + /// Creates a `GenericValue` for use with `ExecutionEngine`s. pub fn create_generic_value(&self, value: f64) -> GenericValue { let value = unsafe { LLVMCreateGenericValueOfFloat(self.as_type_ref(), value) @@ -229,6 +425,20 @@ impl FloatType { GenericValue::new(value) } + /// Creates a constant `ArrayValue`. + /// + /// # Example + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let f32_type = context.f32_type(); + /// let f32_val = f32_type.const_float(0.); + /// let f32_val2 = f32_type.const_float(2.); + /// let f32_array = f32_type.const_array(&[f32_val, f32_val2]); + /// + /// assert!(f32_array.is_const()); + /// ``` pub fn const_array(&self, values: &[FloatValue]) -> ArrayValue { let mut values: Vec = values.iter() .map(|val| val.as_value_ref()) diff --git a/src/types/int_type.rs b/src/types/int_type.rs index fe0ccdbf688..480f089164e 100644 --- a/src/types/int_type.rs +++ b/src/types/int_type.rs @@ -409,7 +409,7 @@ impl IntType { self.int_type.is_sized() } - /// Gets the size of this `IntType`. Value may vary depending on the target machine. + /// Gets the size of this `IntType`. Value may vary depending on the target architecture. /// /// # Example /// @@ -424,7 +424,7 @@ impl IntType { self.int_type.size_of() } - /// Gets the aligment of this `IntType`. Value may vary depending on the target machine. + /// Gets the aligment of this `IntType`. Value may vary depending on the target architecture. /// /// # Example /// @@ -480,7 +480,7 @@ impl IntType { // See Type::print_to_stderr note on 5.0+ status /// Prints the definition of an `IntType` to stderr. Not available in newer LLVM versions. - #[cfg(not(any(feature = "llvm3-6", feature = "llvm5-0")))] + #[cfg(any(feature = "llvm3-7", feature = "llvm3-8", feature = "llvm3-9", feature = "llvm4-0"))] pub fn print_to_stderr(&self) { self.int_type.print_to_stderr() } @@ -516,7 +516,6 @@ impl IntType { /// # Example /// ```no_run /// use inkwell::context::Context; - /// use inkwell::AddressSpace; /// /// let context = Context::create(); /// let i8_type = context.i8_type(); diff --git a/src/types/mod.rs b/src/types/mod.rs index 13efb481881..67b2b21e5ed 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,5 +1,6 @@ mod array_type; mod enums; +#[deny(missing_docs)] mod float_type; mod fn_type; #[deny(missing_docs)] diff --git a/src/types/vec_type.rs b/src/types/vec_type.rs index ec5b9e4cfd6..9b51c6ab57c 100644 --- a/src/types/vec_type.rs +++ b/src/types/vec_type.rs @@ -2,6 +2,7 @@ use llvm_sys::core::{LLVMConstVector, LLVMConstNull, LLVMGetVectorSize, LLVMCons use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; use AddressSpace; +use context::ContextRef; use support::LLVMString; use types::{ArrayType, BasicTypeEnum, Type, traits::AsTypeRef, FunctionType, PointerType}; use values::{AsValueRef, ArrayValue, BasicValue, PointerValue, VectorValue, IntValue}; @@ -124,6 +125,10 @@ impl VectorType { ArrayValue::new(value) } + + pub fn get_context(&self) -> ContextRef { + self.vec_type.get_context() + } } impl AsTypeRef for VectorType { diff --git a/src/values/int_value.rs b/src/values/int_value.rs index adf10911dcd..3921fa311dc 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -3,7 +3,7 @@ use llvm_sys::core::{LLVMConstNot, LLVMConstNeg, LLVMConstNSWNeg, LLVMConstNUWNe use llvm_sys::core::LLVMConstExactUDiv; use llvm_sys::prelude::LLVMValueRef; -use std::ffi::{CStr, CString}; +use std::ffi::CStr; use IntPredicate; use support::LLVMString; diff --git a/src/values/vec_value.rs b/src/values/vec_value.rs index c7206d138d6..d1d5292bab6 100644 --- a/src/values/vec_value.rs +++ b/src/values/vec_value.rs @@ -1,7 +1,7 @@ use llvm_sys::core::{LLVMIsAConstantVector, LLVMIsAConstantDataVector, LLVMConstInsertElement, LLVMConstExtractElement, LLVMIsConstantString, LLVMConstString, LLVMGetElementAsConstant, LLVMGetAsString, LLVMConstSelect, LLVMConstShuffleVector}; use llvm_sys::prelude::LLVMValueRef; -use std::ffi::{CStr, CString}; +use std::ffi::CStr; use support::LLVMString; use types::{VectorType}; diff --git a/tests/all/test_context.rs b/tests/all/test_context.rs index d8da2b10a3d..d4a7f8eb045 100644 --- a/tests/all/test_context.rs +++ b/tests/all/test_context.rs @@ -1,7 +1,8 @@ extern crate inkwell; +use self::inkwell::AddressSpace; use self::inkwell::context::Context; -use self::inkwell::types::IntType; +use self::inkwell::types::{IntType, StructType}; #[test] fn test_no_context_double_free() { @@ -58,3 +59,25 @@ fn test_basic_block_context() { assert_eq!(*basic_block2.get_context(), context); } + +#[test] +fn test_values_get_context() { + let context = Context::create(); + let void_type = context.void_type(); + let i8_type = context.i8_type(); + let f32_type = context.f32_type(); + let f32_vec_type = f32_type.vec_type(3); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_array_type = f32_type.array_type(2); + let fn_type = f32_type.fn_type(&[], false); + let struct_type = StructType::struct_type(&[i8_type.into(), f32_type.into()], false); + + assert_eq!(*f32_type.get_context(), context); + assert_eq!(*void_type.get_context(), context); + assert_eq!(*f32_vec_type.get_context(), context); + assert_eq!(*f32_ptr_type.get_context(), context); + assert_eq!(*f32_array_type.get_context(), context); + assert_eq!(*fn_type.get_context(), context); + assert_eq!(*i8_type.get_context(), context); + assert_eq!(struct_type.get_context(), Context::get_global()); +} diff --git a/tests/all/test_types.rs b/tests/all/test_types.rs index 1196f06aaae..f649d55f7ba 100644 --- a/tests/all/test_types.rs +++ b/tests/all/test_types.rs @@ -365,5 +365,6 @@ fn test_ptr_type() { let i8_type = context.i8_type(); let ptr_type = i8_type.ptr_type(AddressSpace::Generic); + assert_eq!(ptr_type.get_address_space(), AddressSpace::Generic); assert_eq!(ptr_type.get_element_type().into_int_type(), i8_type); } diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index c0b62f5468f..ecda365d03a 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -733,7 +733,7 @@ fn test_function_value_no_params() { } #[test] -fn test_int_from_string() { +fn test_value_from_string() { let context = Context::create(); let i8_type = context.i8_type(); let i8_val = i8_type.const_int_from_string("0121", 10); @@ -753,6 +753,28 @@ fn test_int_from_string() { let i8_val = i8_type.const_int_from_string("ABCD", 2); assert_eq!(*i8_val.print_to_string(), *CString::new("i8 -15").unwrap()); + + // Floats + let f64_type = context.f64_type(); + let f64_val = f64_type.const_float_from_string("3.6"); + + assert_eq!(f64_val.print_to_string().to_string(), "double 3.600000e+00"); + + let f64_val = f64_type.const_float_from_string("3."); + + assert_eq!(f64_val.print_to_string().to_string(), "double 3.000000e+00"); + + let f64_val = f64_type.const_float_from_string("3"); + + assert_eq!(f64_val.print_to_string().to_string(), "double 3.000000e+00"); + + let f64_val = f64_type.const_float_from_string(""); + + assert_eq!(f64_val.print_to_string().to_string(), "double 0.000000e+00"); + + let f64_val = f64_type.const_float_from_string("3.asd"); + + assert_eq!(f64_val.print_to_string().to_string(), "double 0x7FF0000000000000"); } #[test]