Skip to content

Commit

Permalink
feat: Add support for metadata type
Browse files Browse the repository at this point in the history
Closes #153
  • Loading branch information
jubianchi committed May 28, 2021
1 parent 20614c6 commit b6984c0
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 34 deletions.
8 changes: 4 additions & 4 deletions examples/kaleidoscope/main.rs
Expand Up @@ -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::*;
Expand Down Expand Up @@ -982,7 +982,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
compiled_args.push(self.compile_expr(arg)?);
}

let argsv: Vec<BasicValueEnum> = compiled_args.iter().by_ref().map(|&val| val.into()).collect();
let argsv: Vec<BasicMetadataValueEnum> = 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()),
Expand Down Expand Up @@ -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::<Vec<BasicTypeEnum>>();
.collect::<Vec<BasicMetadataTypeEnum>>();
let args_types = args_types.as_slice();

let fn_type = self.context.f64_type().fn_type(args_types, false);
Expand Down
7 changes: 4 additions & 3 deletions src/builder.rs
Expand Up @@ -12,7 +12,7 @@ use llvm_sys::{LLVMTypeKind};
use crate::{AtomicOrdering, AtomicRMWBinOp, IntPredicate, FloatPredicate};
use crate::basic_block::BasicBlock;
use crate::support::to_c_str;
use crate::values::{AggregateValue, AggregateValueEnum, AsValueRef, BasicValue, BasicValueEnum, PhiValue, FunctionValue, IntValue, PointerValue, VectorValue, InstructionValue, GlobalValue, IntMathValue, FloatMathValue, PointerMathValue, InstructionOpcode, CallSiteValue};
use crate::values::{AggregateValue, AggregateValueEnum, AsValueRef, BasicValue, BasicValueEnum, PhiValue, FunctionValue, 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)]
Expand Down Expand Up @@ -125,17 +125,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<F>(&self, function: F, args: &[BasicValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx>
pub fn build_call<F>(&self, function: F, args: &[BasicMetadataValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx>
where
F: Into<FunctionOrPointerValue<'ctx>>,
{
Expand Down
24 changes: 24 additions & 0 deletions 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)]
Expand All @@ -26,6 +28,8 @@ use crate::module::Module;
use crate::support::{to_c_str, LLVMString};
use crate::targets::TargetData;
use crate::types::{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;
Expand Down Expand Up @@ -419,6 +423,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
Expand Down
2 changes: 2 additions & 0 deletions src/module.rs
Expand Up @@ -836,6 +836,8 @@ impl<'ctx> Module<'ctx> {
/// assert_eq!(md_1[1].into_float_value(), f32_val);
/// ```
pub fn add_global_metadata(&self, key: &str, metadata: &MetadataValue<'ctx>) {
assert!(metadata.is_node());

let c_string = to_c_str(key);

unsafe {
Expand Down
3 changes: 2 additions & 1 deletion src/types/array_type.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
}

Expand Down
101 changes: 100 additions & 1 deletion src/types/enums.rs
Expand Up @@ -3,6 +3,8 @@ use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
#[llvm_versions(6.0..=latest)]
use crate::types::MetadataType;
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

Expand Down Expand Up @@ -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 {
Expand All @@ -110,7 +209,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
#[cfg(feature = "llvm11-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(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
Expand Down
3 changes: 2 additions & 1 deletion src/types/float_type.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
}

Expand Down
3 changes: 2 additions & 1 deletion src/types/int_type.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
}

Expand Down
60 changes: 60 additions & 0 deletions src/types/metadata_type.rs
@@ -0,0 +1,60 @@
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> {
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);
/// ```
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);
/// ```
pub fn get_context(self) -> ContextRef<'ctx> {
self.metadata_type.get_context()
}
}

impl AsTypeRef for MetadataType<'_> {
fn as_type_ref(&self) -> LLVMTypeRef {
self.metadata_type.ty
}
}

0 comments on commit b6984c0

Please sign in to comment.