// SPDX-License-Identifier: LGPL-2.1-or-later // Copyright 2018 Jacob Lifshay //! types in backend IR use backend::Context; use std::cell::UnsafeCell; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; #[macro_export] macro_rules! buildable_struct_helper { { struct $name:ident { $($member_name:ident: $member_type:ty,)* } } => { impl $crate::backend::types::BuildableType for $name { fn build<'a, Ty: $crate::backend::types::Type<'a>, TB: $crate::backend::types::TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_struct(&[$(<$member_type as $crate::backend::types::BuildableType>::build(type_builder),)*]) } } impl $crate::backend::types::BuildableStruct for $name { fn get_members( ) -> &'static [$crate::backend::types::BuildableStructMemberDescriptor] { #[allow(dead_code, non_camel_case_types)] #[repr(usize)] enum MemberIndices { $($member_name,)* __Last, } const MEMBERS: &'static [$crate::backend::types::BuildableStructMemberDescriptor] = &[ $($crate::backend::types::BuildableStructMemberDescriptor { name: stringify!($member_name), index: MemberIndices::$member_name as usize, },)* ]; MEMBERS } } } } #[macro_export] macro_rules! buildable_struct { { $(#[derive($derives:ident)])* pub struct $name:ident { $($member_name:ident: $member_type:ty,)* } } => { $(#[derive($derives)])* #[repr(C)] pub struct $name { $($member_name: $member_type,)* } buildable_struct_helper!{ struct $name { $($member_name: $member_type,)* } } }; { $(#[derive($derives:ident)])* struct $name:ident { $($member_name:ident: $member_type:ty,)* } } => { $(#[derive($derives)])* #[repr(C)] struct $name { $($member_name: $member_type,)* } buildable_struct_helper!{ struct $name { $($member_name: $member_type,)* } } }; } /// length of a vector pub enum VectorLength { /// fixed length vector Fixed { /// length in elements length: u32, }, /// variable length vector Variable { /// base length in elements which the runtime vector length is a multiple of base_length: u32, }, } /// equivalent to LLVM's 'Type' pub trait Type<'a>: Clone + Eq + Hash + Debug { /// the `Context` type type Context: Context<'a>; } /// trait for building types pub trait TypeBuilder<'a, Ty: Type<'a>> { /// build a `bool` type fn build_bool(&self) -> Ty; /// build an 8-bit sign-agnostic integer type fn build_i8(&self) -> Ty; /// build an 16-bit sign-agnostic integer type fn build_i16(&self) -> Ty; /// build an 32-bit sign-agnostic integer type fn build_i32(&self) -> Ty; /// build an 64-bit sign-agnostic integer type fn build_i64(&self) -> Ty; /// build an 32-bit IEEE 754 floating-point type fn build_f32(&self) -> Ty; /// build an 64-bit IEEE 754 floating-point type fn build_f64(&self) -> Ty; /// build a pointer fn build_pointer(&self, target: Ty) -> Ty; /// build an array fn build_array(&self, element: Ty, count: usize) -> Ty; /// build a vector fn build_vector(&self, element: Ty, length: VectorLength) -> Ty; /// build a struct fn build_struct(&self, members: &[Ty]) -> Ty; /// build a function type fn build_function(&self, arguments: &[Ty], return_type: Option) -> Ty; /// build a type fn build(&self) -> Ty where Self: Sized, { T::build(self) } } impl<'a, 'b, Ty: Type<'a>> TypeBuilder<'a, Ty> for &'b TypeBuilder<'a, Ty> { fn build_bool(&self) -> Ty { (*self).build_bool() } fn build_i8(&self) -> Ty { (*self).build_i8() } fn build_i16(&self) -> Ty { (*self).build_i16() } fn build_i32(&self) -> Ty { (*self).build_i32() } fn build_i64(&self) -> Ty { (*self).build_i64() } fn build_f32(&self) -> Ty { (*self).build_f32() } fn build_f64(&self) -> Ty { (*self).build_f64() } fn build_pointer(&self, target: Ty) -> Ty { (*self).build_pointer(target) } fn build_array(&self, element: Ty, count: usize) -> Ty { (*self).build_array(element, count) } fn build_vector(&self, element: Ty, length: VectorLength) -> Ty { (*self).build_vector(element, length) } fn build_struct(&self, members: &[Ty]) -> Ty { (*self).build_struct(members) } fn build_function(&self, arguments: &[Ty], return_type: Option) -> Ty { (*self).build_function(arguments, return_type) } } /// trait for rust types that can be built using `TypeBuilder` pub trait BuildableType { /// build the type represented by `Self` fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty; } impl BuildableType for UnsafeCell { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { T::build(type_builder) } } mod hidden { pub trait ScalarBuildableTypeBase {} } impl hidden::ScalarBuildableTypeBase for UnsafeCell {} /// trait for rust types that can be an element of a vector and be built using `TypeBuilder` pub trait ScalarBuildableType: BuildableType + hidden::ScalarBuildableTypeBase {} impl ScalarBuildableType for UnsafeCell {} /// descriptor for members of types implementing `BuildableStruct` pub struct BuildableStructMemberDescriptor { /// name of member pub name: &'static str, /// index of member pub index: usize, } /// trait for structs that can be built using TypeBuilder /// implementing types are usually created using `buildable_struct!` pub trait BuildableStruct: BuildableType { /// get the list of members for `Self` fn get_members() -> &'static [BuildableStructMemberDescriptor]; /// get the member for `Self` that is named `name` fn get_member_by_name(name: &str) -> &'static BuildableStructMemberDescriptor { for member in Self::get_members() { if name == member.name { return member; } } unreachable!("{} is not a member", name); } } macro_rules! build_basic_scalar { ($type:ty, $build_fn:ident) => { impl BuildableType for $type { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.$build_fn() } } impl hidden::ScalarBuildableTypeBase for $type {} impl ScalarBuildableType for $type {} }; } build_basic_scalar!(bool, build_bool); build_basic_scalar!(u8, build_i8); build_basic_scalar!(i8, build_i8); build_basic_scalar!(u16, build_i16); build_basic_scalar!(i16, build_i16); build_basic_scalar!(u32, build_i32); build_basic_scalar!(i32, build_i32); build_basic_scalar!(u64, build_i64); build_basic_scalar!(i64, build_i64); build_basic_scalar!(f32, build_f32); build_basic_scalar!(f64, build_f64); impl<'b, T: BuildableType> BuildableType for Option<&'b T> { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for Option<&'b T> {} impl<'b, T: BuildableType> ScalarBuildableType for Option<&'b T> {} impl<'b, T: BuildableType> BuildableType for Option<&'b mut T> { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for Option<&'b mut T> {} impl<'b, T: BuildableType> ScalarBuildableType for Option<&'b mut T> {} impl<'b, T: BuildableType> BuildableType for &'b T { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for &'b T {} impl<'b, T: BuildableType> ScalarBuildableType for &'b T {} impl<'b, T: BuildableType> BuildableType for &'b mut T { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for &'b mut T {} impl<'b, T: BuildableType> ScalarBuildableType for &'b mut T {} impl BuildableType for *mut T { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for *mut T {} impl<'b, T: BuildableType> ScalarBuildableType for *mut T {} impl BuildableType for *const T { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for *const T {} impl<'b, T: BuildableType> ScalarBuildableType for *const T {} impl BuildableType for NonNull { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for NonNull {} impl<'b, T: BuildableType> ScalarBuildableType for NonNull {} impl BuildableType for Option> { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_pointer(T::build(type_builder)) } } impl<'b, T: BuildableType> hidden::ScalarBuildableTypeBase for Option> {} impl<'b, T: BuildableType> ScalarBuildableType for Option> {} macro_rules! build_unit_function_type { ($($arguments:ident,)*) => { impl<$($arguments: BuildableType),*> BuildableType for Option { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_function(&[$($arguments::build(type_builder),)*], None) } } impl<$($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option {} impl<$($arguments: BuildableType),*> ScalarBuildableType for Option {} impl<$($arguments: BuildableType),*> BuildableType for unsafe extern "C" fn($($arguments,)*) { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_function(&[$($arguments::build(type_builder),)*], None) } } impl<$($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for unsafe extern "C" fn($($arguments,)*) {} impl<$($arguments: BuildableType),*> ScalarBuildableType for unsafe extern "C" fn($($arguments,)*) {} }; } macro_rules! build_function_type { ($($arguments:ident,)*) => { impl BuildableType for Option R> { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_function(&[$($arguments::build(type_builder),)*], Some(R::build(type_builder))) } } impl hidden::ScalarBuildableTypeBase for Option R> {} impl ScalarBuildableType for Option R> {} impl BuildableType for unsafe extern "C" fn($($arguments,)*) -> R { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_function(&[$($arguments::build(type_builder),)*], Some(R::build(type_builder))) } } impl hidden::ScalarBuildableTypeBase for unsafe extern "C" fn($($arguments,)*) -> R {} impl ScalarBuildableType for unsafe extern "C" fn($($arguments,)*) -> R {} }; } macro_rules! build_function_types { () => { build_unit_function_type!(); build_function_type!(); }; ($first_argument:ident, $($arguments:ident,)*) => { build_unit_function_type!($first_argument, $($arguments,)*); build_function_type!($first_argument, $($arguments,)*); build_function_types!($($arguments,)*); } } build_function_types!( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, ); macro_rules! build_array0 { ($length:expr) => { impl BuildableType for [T; $length + 1] { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_array(T::build(type_builder), $length + 1) } } }; } macro_rules! build_array1 { ($length:expr) => { build_array0!($length * 2); build_array0!($length * 2 + 1); }; } macro_rules! build_array2 { ($length:expr) => { build_array1!($length * 2); build_array1!($length * 2 + 1); }; } macro_rules! build_array3 { ($length:expr) => { build_array2!($length * 2); build_array2!($length * 2 + 1); }; } macro_rules! build_array4 { ($length:expr) => { build_array3!($length * 2); build_array3!($length * 2 + 1); }; } macro_rules! build_array5 { ($length:expr) => { build_array4!($length * 2); build_array4!($length * 2 + 1); }; } build_array5!(0); build_array5!(1); /// buildable vector types pub trait Vector: BuildableType { /// element type type Element: ScalarBuildableType; /// vector length const LENGTH: VectorLength; } #[doc(hidden)] pub enum __VectorNeverType {} macro_rules! build_fixed_vector { ($name:ident, $length:expr) => { /// Vector of elements `Element` #[derive(Copy, Clone)] pub struct $name { /// elements of the vector `Self` pub elements: [Element; $length], } impl Deref for $name { type Target = [Element; $length]; fn deref(&self) -> &Self::Target { &self.elements } } impl DerefMut for $name { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.elements } } impl BuildableType for $name { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_vector(Element::build(type_builder), Self::LENGTH) } } impl Vector for $name { type Element = Element; const LENGTH: VectorLength = { VectorLength::Fixed { length: $length } }; } }; } macro_rules! build_variable_vector { ($name:ident, $base_length:expr) => { /// Vector of elements `Element` pub enum $name { #[doc(hidden)] __Dummy(__VectorNeverType, PhantomData), } impl BuildableType for $name { fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { type_builder.build_vector(Element::build(type_builder), Self::LENGTH) } } impl Vector for $name { type Element = Element; const LENGTH: VectorLength = { VectorLength::Variable { base_length: $base_length, } }; } }; } /// alternate name for `VecNx1` pub type VecN = VecNx1; build_fixed_vector!(Vec1, 1); build_fixed_vector!(Vec2, 2); build_fixed_vector!(Vec3, 3); build_fixed_vector!(Vec4, 4); build_fixed_vector!(Vec5, 5); build_fixed_vector!(Vec6, 6); build_fixed_vector!(Vec7, 7); build_fixed_vector!(Vec8, 8); build_fixed_vector!(Vec9, 9); build_fixed_vector!(Vec10, 10); build_fixed_vector!(Vec11, 11); build_fixed_vector!(Vec12, 12); build_fixed_vector!(Vec13, 13); build_fixed_vector!(Vec14, 14); build_fixed_vector!(Vec15, 15); build_fixed_vector!(Vec16, 16); build_variable_vector!(VecNx1, 1); build_variable_vector!(VecNx2, 2); build_variable_vector!(VecNx3, 3); build_variable_vector!(VecNx4, 4); build_variable_vector!(VecNx5, 5); build_variable_vector!(VecNx6, 6); build_variable_vector!(VecNx7, 7); build_variable_vector!(VecNx8, 8); build_variable_vector!(VecNx9, 9); build_variable_vector!(VecNx10, 10); build_variable_vector!(VecNx11, 11); build_variable_vector!(VecNx12, 12); build_variable_vector!(VecNx13, 13); build_variable_vector!(VecNx14, 14); build_variable_vector!(VecNx15, 15); build_variable_vector!(VecNx16, 16);