diff --git a/.travis.yml b/.travis.yml index ffab2e1cb23f7..ff76217197833 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-3.6-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="3.7" @@ -55,7 +55,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-3.7-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="3.8" @@ -68,7 +68,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-3.8-dev - rust: 1.45.2 + rust: 1.52 dist: trusty # 3.9 seems to have a linking issue :/ # - env: @@ -96,7 +96,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-4.0-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="5.0" @@ -109,7 +109,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-5.0-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="6.0" @@ -122,7 +122,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-6.0-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="7.0" @@ -135,7 +135,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-7-dev - rust: 1.45.2 + rust: 1.52 dist: trusty - env: - LLVM_VERSION="8.0" @@ -163,7 +163,7 @@ matrix: packages: - *BASE_PACKAGES - llvm-9-dev - rust: 1.45.2 + rust: 1.52 dist: bionic - env: - LLVM_VERSION="10.0" @@ -179,7 +179,7 @@ matrix: - *BASE_PACKAGES - llvm-10-dev - libclang-common-10-dev - rust: 1.45.2 + rust: 1.52 dist: bionic - env: - LLVM_VERSION="11.0" @@ -195,7 +195,7 @@ matrix: - *BASE_PACKAGES - llvm-11-dev - libclang-common-11-dev - rust: 1.45.2 + rust: 1.52 dist: bionic - env: - LLVM_VERSION="12.0" @@ -211,7 +211,7 @@ matrix: - *BASE_PACKAGES - llvm-12-dev - libclang-common-12-dev - rust: 1.45.2 + rust: 1.52 dist: bionic - deploy: # Documentation build; Only latest supported LLVM version for now provider: pages diff --git a/examples/kaleidoscope/main.rs b/examples/kaleidoscope/main.rs index 5ddf1089126f5..2e199b778961d 100644 --- a/examples/kaleidoscope/main.rs +++ b/examples/kaleidoscope/main.rs @@ -25,8 +25,8 @@ use self::inkwell::builder::Builder; use self::inkwell::context::Context; use self::inkwell::module::Module; use self::inkwell::passes::PassManager; -use self::inkwell::types::BasicTypeEnum; -use self::inkwell::values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, PointerValue}; +use self::inkwell::types::BasicMetadataTypeEnum; +use self::inkwell::values::{BasicValue, BasicMetadataValueEnum, FloatValue, FunctionValue, PointerValue}; use self::inkwell::{OptimizationLevel, FloatPredicate}; use crate::Token::*; @@ -982,7 +982,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> { compiled_args.push(self.compile_expr(arg)?); } - let argsv: Vec = compiled_args.iter().by_ref().map(|&val| val.into()).collect(); + let argsv: Vec = compiled_args.iter().by_ref().map(|&val| val.into()).collect(); match self.builder.build_call(fun, argsv.as_slice(), "tmp").try_as_basic_value().left() { Some(value) => Ok(value.into_float_value()), @@ -1093,7 +1093,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> { let args_types = std::iter::repeat(ret_type) .take(proto.args.len()) .map(|f| f.into()) - .collect::>(); + .collect::>(); let args_types = args_types.as_slice(); let fn_type = self.context.f64_type().fn_type(args_types, false); diff --git a/src/builder.rs b/src/builder.rs index 0dd45f80c82b7..c99c8e1f86780 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -10,7 +10,7 @@ use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef}; use crate::{AtomicOrdering, AtomicRMWBinOp, IntPredicate, FloatPredicate}; use crate::basic_block::BasicBlock; use crate::support::to_c_str; -use crate::values::{AggregateValue, AggregateValueEnum, AsValueRef, FunctionValue, BasicValue, BasicValueEnum, PhiValue, IntValue, PointerValue, VectorValue, InstructionValue, GlobalValue, IntMathValue, FloatMathValue, PointerMathValue, InstructionOpcode, CallSiteValue}; +use crate::values::{AggregateValue, AggregateValueEnum, AsValueRef, FunctionValue, BasicValue, BasicValueEnum, PhiValue, IntValue, PointerValue, VectorValue, InstructionValue, GlobalValue, IntMathValue, FloatMathValue, PointerMathValue, InstructionOpcode, CallSiteValue, BasicMetadataValueEnum}; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; #[llvm_versions(3.9..=latest)] @@ -126,17 +126,18 @@ impl<'ctx> Builder<'ctx> { /// let fn_value = module.add_function("ret", fn_type, None); /// let entry = context.append_basic_block(fn_value, "entry"); /// let i32_arg = fn_value.get_first_param().unwrap(); + /// let md_string = context.metadata_string("a metadata"); /// /// builder.position_at_end(entry); /// - /// let ret_val = builder.build_call(fn_value, &[i32_arg], "call") + /// let ret_val = builder.build_call(fn_value, &[i32_arg.into(), md_string.into()], "call") /// .try_as_basic_value() /// .left() /// .unwrap(); /// /// builder.build_return(Some(&ret_val)); /// ``` - pub fn build_call(&self, function: F, args: &[BasicValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx> + pub fn build_call(&self, function: F, args: &[BasicMetadataValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx> where F: Into>, { diff --git a/src/context.rs b/src/context.rs index 330242f3622bb..f62a8cca62d3a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,8 @@ //! A `Context` is an opaque owner and manager of core global data. use llvm_sys::core::{LLVMAppendBasicBlockInContext, LLVMContextCreate, LLVMContextDispose, LLVMCreateBuilderInContext, LLVMDoubleTypeInContext, LLVMFloatTypeInContext, LLVMFP128TypeInContext, LLVMInsertBasicBlockInContext, LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMModuleCreateWithNameInContext, LLVMStructCreateNamed, LLVMStructTypeInContext, LLVMVoidTypeInContext, LLVMHalfTypeInContext, LLVMGetGlobalContext, LLVMPPCFP128TypeInContext, LLVMConstStructInContext, LLVMMDNodeInContext, LLVMMDStringInContext, LLVMGetMDKindIDInContext, LLVMX86FP80TypeInContext, LLVMConstStringInContext, LLVMContextSetDiagnosticHandler}; +#[llvm_versions(6.0..=latest)] +use llvm_sys::core::LLVMMetadataTypeInContext; #[llvm_versions(3.9..=latest)] use llvm_sys::core::{LLVMCreateEnumAttribute, LLVMCreateStringAttribute}; #[llvm_versions(3.6..7.0)] @@ -28,6 +30,8 @@ use crate::module::Module; use crate::support::{to_c_str, LLVMString}; use crate::targets::TargetData; use crate::types::{AnyTypeEnum, BasicTypeEnum, FloatType, IntType, StructType, VoidType, AsTypeRef, FunctionType}; +#[llvm_versions(6.0..=latest)] +use crate::types::MetadataType; use crate::values::{AsValueRef, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, StructValue, MetadataValue, VectorValue, PointerValue}; use std::marker::PhantomData; @@ -427,6 +431,26 @@ impl Context { } } + /// Gets the `MetadataType` representing 128 bit width. It will be assigned the current context. + /// + /// # Example + /// + /// ``` + /// use inkwell::context::Context; + /// use inkwell::values::IntValue; + /// + /// let context = Context::create(); + /// let md_type = context.metadata_type(); + /// + /// assert_eq!(*md_type.get_context(), context); + /// ``` + #[llvm_versions(6.0..=latest)] + pub fn metadata_type(&self) -> MetadataType { + unsafe { + MetadataType::new(LLVMMetadataTypeInContext(self.context)) + } + } + /// Gets the `IntType` representing a bit width of a pointer. It will be assigned the referenced context. /// /// # Example diff --git a/src/module.rs b/src/module.rs index 09d030b03cc0f..2578609f7a8b7 100644 --- a/src/module.rs +++ b/src/module.rs @@ -818,8 +818,8 @@ impl<'ctx> Module<'ctx> { /// let md_string = context.metadata_string("lots of metadata here"); /// let md_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); /// - /// module.add_global_metadata("my_md", &md_string); - /// module.add_global_metadata("my_md", &md_node); + /// module.add_global_metadata("my_md", &md_string).unwrap(); + /// module.add_global_metadata("my_md", &md_node).unwrap(); /// /// assert_eq!(module.get_global_metadata_size("my_md"), 2); /// @@ -835,12 +835,17 @@ impl<'ctx> Module<'ctx> { /// assert_eq!(md_1[0].into_int_value(), bool_val); /// assert_eq!(md_1[1].into_float_value(), f32_val); /// ``` - pub fn add_global_metadata(&self, key: &str, metadata: &MetadataValue<'ctx>) { - let c_string = to_c_str(key); + pub fn add_global_metadata(&self, key: &str, metadata: &MetadataValue<'ctx>) -> Result<(), &'static str> { + if !metadata.is_node() { + return Err("metadata is expected to be a node.") + } + let c_string = to_c_str(key); unsafe { - LLVMAddNamedMetadataOperand(self.module.get(), c_string.as_ptr(), metadata.as_value_ref()) + LLVMAddNamedMetadataOperand(self.module.get(), c_string.as_ptr(), metadata.as_value_ref()); } + + Ok(()) } // REVIEW: Better name? get_global_metadata_len or _count? @@ -863,8 +868,8 @@ impl<'ctx> Module<'ctx> { /// let md_string = context.metadata_string("lots of metadata here"); /// let md_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); /// - /// module.add_global_metadata("my_md", &md_string); - /// module.add_global_metadata("my_md", &md_node); + /// module.add_global_metadata("my_md", &md_string).unwrap(); + /// module.add_global_metadata("my_md", &md_node).unwrap(); /// /// assert_eq!(module.get_global_metadata_size("my_md"), 2); /// @@ -908,8 +913,8 @@ impl<'ctx> Module<'ctx> { /// let md_string = context.metadata_string("lots of metadata here"); /// let md_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); /// - /// module.add_global_metadata("my_md", &md_string); - /// module.add_global_metadata("my_md", &md_node); + /// module.add_global_metadata("my_md", &md_string).unwrap(); + /// module.add_global_metadata("my_md", &md_node).unwrap(); /// /// assert_eq!(module.get_global_metadata_size("my_md"), 2); /// diff --git a/src/types/array_type.rs b/src/types/array_type.rs index 5ca5849d27d0f..18d242855f9ec 100644 --- a/src/types/array_type.rs +++ b/src/types/array_type.rs @@ -6,6 +6,7 @@ use crate::context::ContextRef; use crate::types::traits::AsTypeRef; use crate::types::{Type, BasicTypeEnum, PointerType, FunctionType}; use crate::values::{AsValueRef, ArrayValue, IntValue}; +use crate::types::enums::BasicMetadataTypeEnum; /// An `ArrayType` is the type of contiguous constants or variables. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -103,7 +104,7 @@ impl<'ctx> ArrayType<'ctx> { /// let i8_array_type = i8_type.array_type(3); /// let fn_type = i8_array_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.array_type.fn_type(param_types, is_var_args) } diff --git a/src/types/enums.rs b/src/types/enums.rs index bb75365e08acb..4d3b5c8677595 100644 --- a/src/types/enums.rs +++ b/src/types/enums.rs @@ -3,10 +3,12 @@ use llvm_sys::LLVMTypeKind; use llvm_sys::prelude::LLVMTypeRef; use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType}; +use crate::types::MetadataType; use crate::types::traits::AsTypeRef; use crate::values::{BasicValue, BasicValueEnum, IntValue}; use std::convert::TryFrom; +use std::iter::FromIterator; macro_rules! enum_type_set { ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => ( @@ -88,6 +90,103 @@ enum_type_set! { VectorType, } } +enum_type_set! { + BasicMetadataTypeEnum: { + ArrayType, + FloatType, + IntType, + PointerType, + StructType, + VectorType, + MetadataType, + } +} + +impl<'ctx> BasicMetadataTypeEnum<'ctx> { + pub fn into_array_type(self) -> ArrayType<'ctx> { + if let BasicMetadataTypeEnum::ArrayType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_float_type(self) -> FloatType<'ctx> { + if let BasicMetadataTypeEnum::FloatType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_int_type(self) -> IntType<'ctx> { + if let BasicMetadataTypeEnum::IntType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_pointer_type(self) -> PointerType<'ctx> { + if let BasicMetadataTypeEnum::PointerType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_struct_type(self) -> StructType<'ctx> { + if let BasicMetadataTypeEnum::StructType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_vector_type(self) -> VectorType<'ctx> { + if let BasicMetadataTypeEnum::VectorType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn into_metadata_type(self) -> MetadataType<'ctx> { + if let BasicMetadataTypeEnum::MetadataType(t) = self { + t + } else { + panic!("Found {:?} but expected another variant", self); + } + } + + pub fn is_array_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::ArrayType(_)) + } + + pub fn is_float_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::FloatType(_)) + } + + pub fn is_int_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::IntType(_)) + } + + pub fn is_metadata_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::MetadataType(_)) + } + + pub fn is_pointer_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::PointerType(_)) + } + + pub fn is_struct_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::StructType(_)) + } + + pub fn is_vector_type(self) -> bool { + matches!(self, BasicMetadataTypeEnum::VectorType(_)) + } +} impl<'ctx> AnyTypeEnum<'ctx> { pub(crate) unsafe fn new(type_: LLVMTypeRef) -> Self { @@ -110,7 +209,7 @@ impl<'ctx> AnyTypeEnum<'ctx> { LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)), #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))] LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)), - LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"), + LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Metadata type is not supported as AnyType."), LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"), #[cfg(feature = "llvm12-0")] LLVMTypeKind::LLVMX86_AMXTypeKind => panic!("FIXME: Unsupported type: AMX"), @@ -378,3 +477,16 @@ impl<'ctx> TryFrom> for BasicTypeEnum<'ctx> { }) } } + +impl<'ctx> From> for BasicMetadataTypeEnum<'ctx> { + fn from(value: BasicTypeEnum<'ctx>) -> Self { + match value { + BasicTypeEnum::ArrayType(at) => at.into(), + BasicTypeEnum::FloatType(ft) => ft.into(), + BasicTypeEnum::IntType(it) => it.into(), + BasicTypeEnum::PointerType(pt) => pt.into(), + BasicTypeEnum::StructType(st) => st.into(), + BasicTypeEnum::VectorType(vt) => vt.into(), + } + } +} diff --git a/src/types/float_type.rs b/src/types/float_type.rs index 32435e672c894..3e769b90ca0be 100644 --- a/src/types/float_type.rs +++ b/src/types/float_type.rs @@ -7,6 +7,7 @@ use crate::context::ContextRef; use crate::types::traits::AsTypeRef; use crate::types::{Type, PointerType, FunctionType, BasicTypeEnum, ArrayType, VectorType}; use crate::values::{AsValueRef, ArrayValue, FloatValue, GenericValue, IntValue}; +use crate::types::enums::BasicMetadataTypeEnum; /// A `FloatType` is the type of a floating point constant or variable. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -34,7 +35,7 @@ impl<'ctx> FloatType<'ctx> { /// let f32_type = context.f32_type(); /// let fn_type = f32_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.float_type.fn_type(param_types, is_var_args) } diff --git a/src/types/int_type.rs b/src/types/int_type.rs index 39f204f740f95..e86e99faa9b43 100644 --- a/src/types/int_type.rs +++ b/src/types/int_type.rs @@ -10,6 +10,7 @@ use crate::types::{Type, ArrayType, BasicTypeEnum, VectorType, PointerType, Func use crate::values::{AsValueRef, ArrayValue, GenericValue, IntValue}; use std::convert::TryFrom; +use crate::types::enums::BasicMetadataTypeEnum; /// How to interpret a string or digits used to construct an integer constant. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -195,7 +196,7 @@ impl<'ctx> IntType<'ctx> { /// let i8_type = context.i8_type(); /// let fn_type = i8_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.int_type.fn_type(param_types, is_var_args) } diff --git a/src/types/metadata_type.rs b/src/types/metadata_type.rs new file mode 100644 index 0000000000000..921ebfe0bd704 --- /dev/null +++ b/src/types/metadata_type.rs @@ -0,0 +1,69 @@ +use llvm_sys::prelude::LLVMTypeRef; + +use crate::context::ContextRef; +use crate::types::traits::AsTypeRef; +use crate::types::{Type, FunctionType, BasicTypeEnum, ArrayType, VectorType}; +use crate::values::{IntValue, MetadataValue}; +use crate::types::enums::BasicMetadataTypeEnum; + +/// A `MetadataType` is the type of a metadata. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct MetadataType<'ctx> { + metadata_type: Type<'ctx>, +} + +impl<'ctx> MetadataType<'ctx> { + #[llvm_versions(6.0..=latest)] + pub(crate) unsafe fn new(metadata_type: LLVMTypeRef) -> Self { + assert!(!metadata_type.is_null()); + + MetadataType { + metadata_type: Type::new(metadata_type), + } + } + + /// Creates a `FunctionType` with this `MetadataType` for its return type. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let md_type = context.metadata_type(); + /// let fn_type = md_type.fn_type(&[], false); + /// ``` + #[llvm_versions(6.0..=latest)] + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + self.metadata_type.fn_type(param_types, is_var_args) + } + + /// Gets a reference to the `Context` this `MetadataType` was created in. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let md_type = context.metadata_type(); + /// + /// assert_eq!(*md_type.get_context(), context); + /// ``` + #[llvm_versions(6.0..=latest)] + pub fn get_context(self) -> ContextRef<'ctx> { + self.metadata_type.get_context() + } +} + +impl AsTypeRef for MetadataType<'_> { + #[llvm_versions(6.0..=latest)] + fn as_type_ref(&self) -> LLVMTypeRef { + self.metadata_type.ty + } + + #[llvm_versions(3.6..6.0)] + fn as_type_ref(&self) -> LLVMTypeRef { + unimplemented!("MetadataType is only available in LLVM > 6.0") + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index a498fdea466f4..d876cf358e28f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -10,6 +10,8 @@ mod fn_type; #[deny(missing_docs)] mod int_type; #[deny(missing_docs)] +mod metadata_type; +#[deny(missing_docs)] mod ptr_type; #[deny(missing_docs)] mod struct_type; @@ -21,10 +23,11 @@ mod vec_type; mod void_type; pub use crate::types::array_type::ArrayType; -pub use crate::types::enums::{AnyTypeEnum, BasicTypeEnum}; +pub use crate::types::enums::{AnyTypeEnum, BasicTypeEnum, BasicMetadataTypeEnum}; pub use crate::types::float_type::FloatType; pub use crate::types::fn_type::FunctionType; pub use crate::types::int_type::{IntType, StringRadix}; +pub use crate::types::metadata_type::MetadataType; pub use crate::types::ptr_type::PointerType; pub use crate::types::struct_type::StructType; pub use crate::types::traits::{AnyType, BasicType, IntMathType, FloatMathType, PointerMathType}; @@ -32,9 +35,10 @@ pub use crate::types::vec_type::VectorType; pub use crate::types::void_type::VoidType; pub(crate) use crate::types::traits::AsTypeRef; +use llvm_sys::LLVMTypeKind; #[llvm_versions(3.7..=4.0)] use llvm_sys::core::LLVMDumpType; -use llvm_sys::core::{LLVMAlignOf, LLVMGetTypeContext, LLVMFunctionType, LLVMArrayType, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString, LLVMTypeIsSized, LLVMSizeOf, LLVMVectorType, LLVMGetElementType, LLVMConstNull}; +use llvm_sys::core::{LLVMAlignOf, LLVMGetTypeContext, LLVMFunctionType, LLVMArrayType, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString, LLVMTypeIsSized, LLVMSizeOf, LLVMVectorType, LLVMGetElementType, LLVMConstNull, LLVMGetTypeKind, LLVMConstPointerNull}; use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; #[cfg(feature = "experimental")] use static_alloc::Bump; @@ -78,7 +82,10 @@ impl<'ctx> Type<'ctx> { fn const_zero(self) -> LLVMValueRef { unsafe { - LLVMConstNull(self.ty) + match LLVMGetTypeKind(self.ty) { + LLVMTypeKind::LLVMMetadataTypeKind => LLVMConstPointerNull(self.ty), + _ => LLVMConstNull(self.ty) + } } } @@ -98,7 +105,7 @@ impl<'ctx> Type<'ctx> { } #[cfg(not(feature = "experimental"))] - fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { let mut param_types: Vec = param_types.iter() .map(|val| val.as_type_ref()) .collect(); @@ -108,7 +115,7 @@ impl<'ctx> Type<'ctx> { } #[cfg(feature = "experimental")] - fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { let pool: Bump<[usize; 16]> = Bump::uninit(); let mut pool_start = None; diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs index 6b671cfc6e4bb..43c3476b7e6f8 100644 --- a/src/types/ptr_type.rs +++ b/src/types/ptr_type.rs @@ -8,6 +8,7 @@ use crate::types::{AnyTypeEnum, BasicTypeEnum, ArrayType, FunctionType, Type, Ve use crate::values::{AsValueRef, ArrayValue, PointerValue, IntValue}; use std::convert::TryFrom; +use crate::types::enums::BasicMetadataTypeEnum; /// A `PointerType` is the type of a pointer constant or variable. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -109,7 +110,7 @@ impl<'ctx> PointerType<'ctx> { /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); /// let fn_type = f32_ptr_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.ptr_type.fn_type(param_types, is_var_args) } diff --git a/src/types/struct_type.rs b/src/types/struct_type.rs index 20e3c0dba7d38..40b44061c71e6 100644 --- a/src/types/struct_type.rs +++ b/src/types/struct_type.rs @@ -11,6 +11,7 @@ use crate::context::ContextRef; use crate::types::traits::AsTypeRef; use crate::types::{ArrayType, BasicTypeEnum, PointerType, FunctionType, Type}; use crate::values::{ArrayValue, BasicValueEnum, StructValue, IntValue, AsValueRef}; +use crate::types::enums::BasicMetadataTypeEnum; /// A `StructType` is the type of a heterogeneous container of types. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -210,7 +211,7 @@ impl<'ctx> StructType<'ctx> { /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false); /// let fn_type = struct_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.struct_type.fn_type(param_types, is_var_args) } diff --git a/src/types/traits.rs b/src/types/traits.rs index 587a7b0d4fc4e..ab7748623574b 100644 --- a/src/types/traits.rs +++ b/src/types/traits.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use crate::AddressSpace; use crate::types::{IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VectorType, VoidType, Type}; -use crate::types::enums::{AnyTypeEnum, BasicTypeEnum}; +use crate::types::enums::{AnyTypeEnum, BasicTypeEnum, BasicMetadataTypeEnum}; use crate::values::{IntMathValue, FloatMathValue, PointerMathValue, IntValue, FloatValue, PointerValue, VectorValue}; use crate::support::LLVMString; @@ -62,7 +62,7 @@ pub trait BasicType<'ctx>: AnyType<'ctx> { /// let int_basic_type = int.as_basic_type_enum(); /// assert_eq!(int_basic_type.fn_type(&[], false), int.fn_type(&[], false)); /// ``` - fn fn_type(&self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + fn fn_type(&self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { unsafe { Type::new(self.as_type_ref()).fn_type(param_types, is_var_args) } diff --git a/src/types/vec_type.rs b/src/types/vec_type.rs index 03bc3f1cdd202..6f5207a5c0d46 100644 --- a/src/types/vec_type.rs +++ b/src/types/vec_type.rs @@ -5,6 +5,7 @@ use crate::AddressSpace; use crate::context::ContextRef; use crate::types::{ArrayType, BasicTypeEnum, Type, traits::AsTypeRef, FunctionType, PointerType}; use crate::values::{AsValueRef, ArrayValue, BasicValue, VectorValue, IntValue}; +use crate::types::enums::BasicMetadataTypeEnum; /// A `VectorType` is the type of a multiple value SIMD constant or variable. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -204,7 +205,7 @@ impl<'ctx> VectorType<'ctx> { /// let f32_vec_type = f32_type.vec_type(3); /// let fn_type = f32_vec_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.vec_type.fn_type(param_types, is_var_args) } diff --git a/src/types/void_type.rs b/src/types/void_type.rs index aa01ae563c920..24728773b9403 100644 --- a/src/types/void_type.rs +++ b/src/types/void_type.rs @@ -3,6 +3,7 @@ use llvm_sys::prelude::LLVMTypeRef; use crate::context::ContextRef; use crate::types::traits::AsTypeRef; use crate::types::{Type, BasicTypeEnum, FunctionType}; +use crate::types::enums::BasicMetadataTypeEnum; /// A `VoidType` is a special type with no possible direct instances. It's only /// useful as a function return type. @@ -66,7 +67,7 @@ impl<'ctx> VoidType<'ctx> { /// let void_type = context.void_type(); /// let fn_type = void_type.fn_type(&[], false); /// ``` - pub fn fn_type(self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { + pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { self.void_type.fn_type(param_types, is_var_args) } diff --git a/src/values/callable_value.rs b/src/values/callable_value.rs index e0352bdac58c3..bd72a66926a34 100644 --- a/src/values/callable_value.rs +++ b/src/values/callable_value.rs @@ -31,7 +31,7 @@ use llvm_sys::LLVMTypeKind; /// /// builder.position_at_end(entry); /// -/// let ret_val = builder.build_call(fn_value, &[i32_arg], "call") +/// let ret_val = builder.build_call(fn_value, &[i32_arg.into()], "call") /// .try_as_basic_value() /// .left() /// .unwrap(); @@ -66,7 +66,7 @@ use llvm_sys::LLVMTypeKind; /// // explicitly handling the failure case (here with `unwrap`) /// let callable_value = CallableValue::try_from(fn_pointer_value).unwrap(); /// -/// let ret_val = builder.build_call(callable_value, &[i32_arg], "call") +/// let ret_val = builder.build_call(callable_value, &[i32_arg.into()], "call") /// .try_as_basic_value() /// .left() /// .unwrap(); diff --git a/src/values/enums.rs b/src/values/enums.rs index aa8f4d2b424a0..8e4ba8a702036 100644 --- a/src/values/enums.rs +++ b/src/values/enums.rs @@ -449,6 +449,14 @@ impl<'ctx> From> for AnyValueEnum<'ctx> { } } +impl<'ctx> From> for BasicMetadataValueEnum<'ctx> { + fn from(value: BasicValueEnum<'ctx>) -> Self { + unsafe { + BasicMetadataValueEnum::new(value.as_value_ref()) + } + } +} + impl<'ctx> TryFrom> for BasicValueEnum<'ctx> { type Error = (); diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index 86244d13c2bed..2caed364b864d 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -664,10 +664,16 @@ impl<'ctx> InstructionValue<'ctx> { /// Determines whether or not this `Instruction` has any associated metadata /// `kind_id`. - pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) { + pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) -> Result<(), &'static str> { + if !metadata.is_node() { + return Err("metadata is expected to be a node.") + } + unsafe { - LLVMSetMetadata(self.instruction_value.value, kind_id, metadata.as_value_ref()) + LLVMSetMetadata(self.instruction_value.value, kind_id, metadata.as_value_ref()); } + + Ok(()) } } diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index d1df018362c6a..c3de417286aea 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -401,128 +401,135 @@ fn test_metadata() { assert_eq!(context.get_kind_id("irr_loop"), 24); } - // TODO: 7+? - - assert_eq!(module.get_global_metadata_size("my_string_md"), 0); - assert_eq!(module.get_global_metadata("my_string_md").len(), 0); - - let md_string = context.metadata_string("lots of metadata here"); - - assert_eq!(md_string.get_node_size(), 0); - assert_eq!(md_string.get_node_values().len(), 0); - assert_eq!(md_string.get_string_value().unwrap().to_str(), Ok("lots of metadata here")); - - 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(); - // let fn_type = bool_type.fn_type(&[i64_type.into(), array_type.into()], false); - - 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 ppc_f128_val = ppc_f128_type.const_float(0.0); - // let ptr_val = bool_type.ptr_type(AddressSpace::Generic).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 fn_val = module.add_function("my_fn", fn_type, None); - - let md_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); - - let node_values = md_node.get_node_values(); - - assert_eq!(md_node.get_string_value(), None); - assert_eq!(node_values.len(), 2); - assert_eq!(node_values[0].into_int_value(), bool_val); - assert_eq!(node_values[1].into_float_value(), f32_val); - - module.add_global_metadata("my_md", &md_string); - module.add_global_metadata("my_md", &md_node); - - assert_eq!(module.get_global_metadata_size("my_md"), 2); - - let global_md = module.get_global_metadata("my_md"); - - assert_eq!(global_md.len(), 2); - - let (md_0, md_1) = (global_md[0].get_node_values(), global_md[1].get_node_values()); - - assert_eq!(md_0.len(), 1); - assert_eq!(md_1.len(), 2); - assert_eq!(md_0[0].into_metadata_value().get_string_value(), md_string.get_string_value()); - assert_eq!(md_1[0].into_int_value(), bool_val); - assert_eq!(md_1[1].into_float_value(), f32_val); - - assert_eq!(module.get_global_metadata_size("other_md"), 0); - - // REVIEW: const_null_ptr/ ptr.const_null seem to cause UB. Need to test and adapt - // and see if they should be allowed to have metadata? Also, while we're at it we should - // try with undef - - // REVIEW: initial has_metadata seems inconsistent. Some have it. Some don't for kind_id 0. Some sometimes have it. - // furthermore, when they do have it, it is a SF when printing out. Unclear what can be done here. Maybe just disallow index 0? - // assert!(bool_val.has_metadata()); - // assert!(i8_val.has_metadata()); - // assert!(i16_val.has_metadata()); - // assert!(i32_val.has_metadata()); - // assert!(i64_val.has_metadata()); - // assert!(!i128_val.has_metadata()); - // assert!(!f16_val.has_metadata()); - // assert!(!f32_val.has_metadata()); - // assert!(!f64_val.has_metadata()); - // assert!(!f128_val.has_metadata()); - // assert!(!ppc_f128_val.has_metadata()); - // assert!(ptr_val.has_metadata()); - // assert!(array_val.has_metadata()); - // assert!(struct_val.has_metadata()); - // assert!(!vec_val.has_metadata()); - // assert!(!fn_val.has_metadata()); - - let builder = context.create_builder(); - let module = context.create_module("my_mod"); - let void_type = context.void_type(); - let bool_type = context.bool_type(); - let fn_type = void_type.fn_type(&[bool_type.into()], false); - let fn_value = module.add_function("my_func", fn_type, None); - - let entry_block = context.append_basic_block(fn_value, "entry"); - - builder.position_at_end(entry_block); - - let ret_instr = builder.build_return(None); - - ret_instr.set_metadata(md_string, 2); - - assert!(ret_instr.has_metadata()); - assert!(ret_instr.get_metadata(1).is_none()); - - let md_node_values = ret_instr.get_metadata(2).unwrap().get_node_values(); - - assert_eq!(md_node_values.len(), 1); - assert_eq!(md_node_values[0].into_metadata_value().get_string_value(), md_string.get_string_value()); - - // New Context Metadata - let context_metadata_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); - let context_metadata_string = context.metadata_string("my_context_metadata"); + #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7", feature = "llvm3-8", feature = "llvm3-9", + feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] + { - assert!(context_metadata_node.is_node()); - assert!(context_metadata_string.is_string()); + assert_eq!(module.get_global_metadata_size("my_string_md"), 0); + assert_eq!(module.get_global_metadata("my_string_md").len(), 0); + + let md_string = context.metadata_string("lots of metadata here"); + + assert_eq!(md_string.get_node_size(), 0); + assert_eq!(md_string.get_node_values().len(), 0); + assert_eq!(md_string.get_string_value().unwrap().to_str(), Ok("lots of metadata here")); + + 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(); + // let fn_type = bool_type.fn_type(&[i64_type.into(), array_type.into()], false); + + 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 ppc_f128_val = ppc_f128_type.const_float(0.0); + // let ptr_val = bool_type.ptr_type(AddressSpace::Generic).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 fn_val = module.add_function("my_fn", fn_type, None); + + let md_node_child = context.metadata_node(&[bool_val.into(), f32_val.into()]); + let md_node = context.metadata_node(&[bool_val.into(), f32_val.into(), md_string.into(), md_node_child.into()]); + + let node_values = md_node.get_node_values(); + + assert_eq!(md_node.get_string_value(), None); + assert_eq!(node_values.len(), 4); + assert_eq!(node_values[0].into_int_value(), bool_val); + assert_eq!(node_values[1].into_float_value(), f32_val); + assert_eq!(node_values[2].into_metadata_value().get_string_value(), md_string.get_string_value()); + assert!(node_values[3].into_metadata_value().is_node()); + + assert!(module.add_global_metadata("my_md", &md_string).is_err()); + module.add_global_metadata("my_md", &md_node).unwrap(); + + assert_eq!(module.get_global_metadata_size("my_md"), 1); + + let global_md = module.get_global_metadata("my_md"); + + assert_eq!(global_md.len(), 1); + + let md = global_md[0].get_node_values(); + + assert_eq!(md.len(), 4); + assert_eq!(md[0].into_int_value(), bool_val); + assert_eq!(md[1].into_float_value(), f32_val); + assert_eq!(md[2].into_metadata_value().get_string_value(), md_string.get_string_value()); + assert!(md[3].into_metadata_value().is_node()); + + assert_eq!(module.get_global_metadata_size("other_md"), 0); + + // REVIEW: const_null_ptr/ ptr.const_null seem to cause UB. Need to test and adapt + // and see if they should be allowed to have metadata? Also, while we're at it we should + // try with undef + + // REVIEW: initial has_metadata seems inconsistent. Some have it. Some don't for kind_id 0. Some sometimes have it. + // furthermore, when they do have it, it is a SF when printing out. Unclear what can be done here. Maybe just disallow index 0? + // assert!(bool_val.has_metadata()); + // assert!(i8_val.has_metadata()); + // assert!(i16_val.has_metadata()); + // assert!(i32_val.has_metadata()); + // assert!(i64_val.has_metadata()); + // assert!(!i128_val.has_metadata()); + // assert!(!f16_val.has_metadata()); + // assert!(!f32_val.has_metadata()); + // assert!(!f64_val.has_metadata()); + // assert!(!f128_val.has_metadata()); + // assert!(!ppc_f128_val.has_metadata()); + // assert!(ptr_val.has_metadata()); + // assert!(array_val.has_metadata()); + // assert!(struct_val.has_metadata()); + // assert!(!vec_val.has_metadata()); + // assert!(!fn_val.has_metadata()); + + let builder = context.create_builder(); + let module = context.create_module("my_mod"); + let void_type = context.void_type(); + let bool_type = context.bool_type(); + let fn_type = void_type.fn_type(&[bool_type.into()], false); + let fn_value = module.add_function("my_func", fn_type, None); + + let entry_block = context.append_basic_block(fn_value, "entry"); + + builder.position_at_end(entry_block); + + let ret_instr = builder.build_return(None); + let ret_instr_md = context.metadata_node(&[md_string.into()]); + + ret_instr.set_metadata(ret_instr_md, 2); + + assert!(ret_instr.has_metadata()); + assert!(ret_instr.get_metadata(1).is_none()); + + let md_node_values = ret_instr.get_metadata(2).unwrap().get_node_values(); + + assert_eq!(md_node_values.len(), 1); + assert_eq!(md_node_values[0].into_metadata_value().get_string_value(), md_string.get_string_value()); + + // New Context Metadata + let context_metadata_node = context.metadata_node(&[bool_val.into(), f32_val.into()]); + let context_metadata_string = context.metadata_string("my_context_metadata"); + + assert!(context_metadata_node.is_node()); + assert!(context_metadata_string.is_string()); + } } #[test]