completed shader compiler backend type system
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 9 Oct 2018 09:21:50 +0000 (02:21 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 9 Oct 2018 09:21:50 +0000 (02:21 -0700)
shader-compiler-llvm-7/src/backend.rs
shader-compiler/src/lib.rs

index d3c743744e4d7ff4233df57b859e5209b353319c..74af1b523550289731a9f30d4261c484dadce264 100644 (file)
@@ -5,7 +5,7 @@ use shader_compiler::backend::*;
 use std::ffi::{CStr, CString};
 use std::fmt;
 use std::ops::Deref;
-use std::os::raw::c_char;
+use std::os::raw::{c_char, c_uint};
 use std::ptr::NonNull;
 
 #[derive(Clone)]
@@ -78,8 +78,7 @@ pub struct LLVM7TypeBuilder {
     variable_vector_length_multiplier: u32,
 }
 
-impl<'a> TypeBuilder<'a> for LLVM7TypeBuilder {
-    type Type = LLVM7Type;
+impl<'a> TypeBuilder<'a, LLVM7Type> for LLVM7TypeBuilder {
     fn build_bool(&self) -> LLVM7Type {
         unsafe { LLVM7Type(llvm_sys::core::LLVMInt1TypeInContext(self.context)) }
     }
@@ -118,6 +117,32 @@ impl<'a> TypeBuilder<'a> for LLVM7TypeBuilder {
         assert_ne!(length, 0);
         unsafe { LLVM7Type(llvm_sys::core::LLVMVectorType(element.0, length)) }
     }
+    fn build_struct(&self, members: &[LLVM7Type]) -> LLVM7Type {
+        assert_eq!(members.len() as c_uint as usize, members.len());
+        unsafe {
+            LLVM7Type(llvm_sys::core::LLVMStructTypeInContext(
+                self.context,
+                members.as_ptr() as *mut llvm_sys::prelude::LLVMTypeRef,
+                members.len() as c_uint,
+                false as llvm_sys::prelude::LLVMBool,
+            ))
+        }
+    }
+    fn build_function(&self, arguments: &[LLVM7Type], return_type: Option<LLVM7Type>) -> LLVM7Type {
+        assert_eq!(arguments.len() as c_uint as usize, arguments.len());
+        unsafe {
+            LLVM7Type(llvm_sys::core::LLVMFunctionType(
+                return_type
+                    .unwrap_or_else(|| {
+                        LLVM7Type(llvm_sys::core::LLVMVoidTypeInContext(self.context))
+                    })
+                    .0,
+                arguments.as_ptr() as *mut llvm_sys::prelude::LLVMTypeRef,
+                arguments.len() as c_uint,
+                false as llvm_sys::prelude::LLVMBool,
+            ))
+        }
+    }
 }
 
 pub struct LLVM7Context {
index b18870956c55b67a690bbb442b031f456df2ffcd..fe2ab5df9d4145ee437ddc51368096150518ce61 100644 (file)
@@ -4,11 +4,87 @@
 
 //! Shader Compiler for Kazan
 
+#[macro_export]
+macro_rules! buildable_struct_helper {
+    {
+        struct $name:ident {
+            $($member_name:ident: $member_type:ty,)*
+        }
+    } => {
+        impl $crate::backend::BuildableType for $name {
+            fn build<'a, Ty: $crate::backend::Type<'a>, TB: $crate::backend::TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+                type_builder.build_struct(&[$(<$member_type as $crate::backend::BuildableType>::build(type_builder),)*])
+            }
+        }
+
+        impl $crate::backend::BuildableStruct for $name {
+            fn get_members(
+            ) -> &'static [$crate::backend::BuildableStructMemberDescriptor] {
+                #[allow(dead_code, non_camel_case_types)]
+                #[repr(usize)]
+                enum MemberIndices {
+                    $($member_name,)*
+                    __Last,
+                }
+                const MEMBERS: &'static [$crate::backend::BuildableStructMemberDescriptor] = &[
+                    $($crate::backend::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,)*
+            }
+        }
+    };
+}
+
 /// Shader Compiler Backend traits
 pub mod backend {
+    use std::cell::UnsafeCell;
     use std::fmt::Debug;
     use std::hash::Hash;
     use std::marker::PhantomData;
+    use std::ops::{Deref, DerefMut};
 
     /// length of a vector
     pub enum VectorLength {
@@ -28,52 +104,136 @@ pub mod backend {
     pub trait Type<'a>: Clone + Eq + Hash + Debug {}
 
     /// trait for building types
-    pub trait TypeBuilder<'a>: Sized {
-        /// the `Type` type
-        type Type: Type<'a>;
+    pub trait TypeBuilder<'a, Ty: Type<'a>> {
         /// build a `bool` type
-        fn build_bool(&self) -> Self::Type;
+        fn build_bool(&self) -> Ty;
         /// build an 8-bit sign-agnostic integer type
-        fn build_i8(&self) -> Self::Type;
+        fn build_i8(&self) -> Ty;
         /// build an 16-bit sign-agnostic integer type
-        fn build_i16(&self) -> Self::Type;
+        fn build_i16(&self) -> Ty;
         /// build an 32-bit sign-agnostic integer type
-        fn build_i32(&self) -> Self::Type;
+        fn build_i32(&self) -> Ty;
         /// build an 64-bit sign-agnostic integer type
-        fn build_i64(&self) -> Self::Type;
+        fn build_i64(&self) -> Ty;
         /// build an 32-bit IEEE 754 floating-point type
-        fn build_f32(&self) -> Self::Type;
+        fn build_f32(&self) -> Ty;
         /// build an 64-bit IEEE 754 floating-point type
-        fn build_f64(&self) -> Self::Type;
+        fn build_f64(&self) -> Ty;
         /// build a pointer
-        fn build_pointer(&self, target: Self::Type) -> Self::Type;
+        fn build_pointer(&self, target: Ty) -> Ty;
         /// build an array
-        fn build_array(&self, element: Self::Type, count: usize) -> Self::Type;
+        fn build_array(&self, element: Ty, count: usize) -> Ty;
         /// build a vector
-        fn build_vector(&self, element: Self::Type, length: VectorLength) -> Self::Type;
+        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>) -> Ty;
         /// build a type
-        fn build<T: BuildableType>(&self) -> Self::Type {
+        fn build<T: BuildableType>(&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>) -> 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, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type;
+        fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty;
     }
 
+    impl<T: BuildableType> BuildableType for UnsafeCell<T> {
+        fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+            T::build(type_builder)
+        }
+    }
+
+    mod hidden {
+        pub trait ScalarBuildableTypeBase {}
+    }
+
+    impl<T: hidden::ScalarBuildableTypeBase> hidden::ScalarBuildableTypeBase for UnsafeCell<T> {}
+
     /// trait for rust types that can be an element of a vector and be built using `TypeBuilder`
-    pub trait ScalarBuildableType: BuildableType {}
+    pub trait ScalarBuildableType: BuildableType + hidden::ScalarBuildableTypeBase {}
+
+    impl<T: ScalarBuildableType> ScalarBuildableType for UnsafeCell<T> {}
+
+    /// 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, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::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 {}
         };
     }
@@ -91,41 +251,93 @@ pub mod backend {
     build_basic_scalar!(f64, build_f64);
 
     impl<'b, T: BuildableType> BuildableType for &'b T {
-        fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+        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, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+        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<T: BuildableType> BuildableType for *mut T {
-        fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+        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<T: BuildableType> BuildableType for *const T {
-        fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+        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 {}
 
+    macro_rules! build_unit_function_type {
+        ($($arguments:ident,)*) => {
+            impl<$($arguments: BuildableType),*> BuildableType for Option<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 Option<unsafe extern "C" fn($($arguments,)*)> {}
+
+            impl<$($arguments: BuildableType),*> ScalarBuildableType for Option<unsafe extern "C" fn($($arguments,)*)> {}
+        };
+    }
+
+    macro_rules! build_function_type {
+        ($($arguments:ident,)*) => {
+            impl<R: BuildableType, $($arguments: BuildableType),*> BuildableType for Option<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<R: BuildableType, $($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option<unsafe extern "C" fn($($arguments,)*) -> R> {}
+
+            impl<R: BuildableType, $($arguments: BuildableType),*> ScalarBuildableType for Option<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<T: BuildableType> BuildableType for [T; $length + 1] {
-                fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+                fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
                     type_builder.build_array(T::build(type_builder), $length + 1)
                 }
             }
@@ -178,13 +390,54 @@ pub mod backend {
         const LENGTH: VectorLength;
     }
 
-    macro_rules! build_vector {
+    #[doc(hidden)]
+    pub enum __VectorNeverType {}
+
+    macro_rules! build_fixed_vector {
         ($name:ident, $length:expr) => {
             /// Vector of elements `Element`
-            pub struct $name<Element: ScalarBuildableType>(PhantomData<*const Element>);
+            #[derive(Copy, Clone)]
+            pub struct $name<Element: ScalarBuildableType> {
+                /// elements of the vector `Self`
+                pub elements: [Element; $length],
+            }
+
+            impl<Element: ScalarBuildableType> Deref for $name<Element> {
+                type Target = [Element; $length];
+                fn deref(&self) -> &Self::Target {
+                    &self.elements
+                }
+            }
+
+            impl<Element: ScalarBuildableType> DerefMut for $name<Element> {
+                fn deref_mut(&mut self) -> &mut Self::Target {
+                    &mut self.elements
+                }
+            }
+
+            impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
+                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<Element: ScalarBuildableType> Vector for $name<Element> {
+                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<Element: ScalarBuildableType> {
+                #[doc(hidden)]
+                __Dummy(__VectorNeverType, PhantomData<Element>),
+            }
 
             impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
-                fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+                fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
                     type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
                 }
             }
@@ -192,47 +445,49 @@ pub mod backend {
             impl<Element: ScalarBuildableType> Vector for $name<Element> {
                 type Element = Element;
                 const LENGTH: VectorLength = {
-                    use self::VectorLength::*;
-                    $length
+                    VectorLength::Variable {
+                        base_length: $base_length,
+                    }
                 };
             }
         };
     }
 
-    build_vector!(Vec1, Fixed { length: 1 });
-    build_vector!(VecN, Variable { base_length: 1 });
-    /// alternate name for VecN
-    pub type VecNx1<Element> = VecN<Element>;
-    build_vector!(Vec2, Fixed { length: 2 });
-    build_vector!(VecNx2, Variable { base_length: 2 });
-    build_vector!(Vec3, Fixed { length: 3 });
-    build_vector!(VecNx3, Variable { base_length: 3 });
-    build_vector!(Vec4, Fixed { length: 4 });
-    build_vector!(VecNx4, Variable { base_length: 4 });
-    build_vector!(Vec5, Fixed { length: 5 });
-    build_vector!(VecNx5, Variable { base_length: 5 });
-    build_vector!(Vec6, Fixed { length: 6 });
-    build_vector!(VecNx6, Variable { base_length: 6 });
-    build_vector!(Vec7, Fixed { length: 7 });
-    build_vector!(VecNx7, Variable { base_length: 7 });
-    build_vector!(Vec8, Fixed { length: 8 });
-    build_vector!(VecNx8, Variable { base_length: 8 });
-    build_vector!(Vec9, Fixed { length: 9 });
-    build_vector!(VecNx9, Variable { base_length: 9 });
-    build_vector!(Vec10, Fixed { length: 10 });
-    build_vector!(VecNx10, Variable { base_length: 10 });
-    build_vector!(Vec11, Fixed { length: 11 });
-    build_vector!(VecNx11, Variable { base_length: 11 });
-    build_vector!(Vec12, Fixed { length: 12 });
-    build_vector!(VecNx12, Variable { base_length: 12 });
-    build_vector!(Vec13, Fixed { length: 13 });
-    build_vector!(VecNx13, Variable { base_length: 13 });
-    build_vector!(Vec14, Fixed { length: 14 });
-    build_vector!(VecNx14, Variable { base_length: 14 });
-    build_vector!(Vec15, Fixed { length: 15 });
-    build_vector!(VecNx15, Variable { base_length: 15 });
-    build_vector!(Vec16, Fixed { length: 16 });
-    build_vector!(VecNx16, Variable { base_length: 16 });
+    /// alternate name for `VecNx1`
+    pub type VecN<Element> = VecNx1<Element>;
+
+    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);
 
     /// equivalent to LLVM's 'IRBuilder'
     pub trait Builder<'a> {}
@@ -252,7 +507,7 @@ pub mod backend {
         /// the `Type` type
         type Type: Type<'a>;
         /// the `TypeBuilder` type
-        type TypeBuilder: TypeBuilder<'a, Type = Self::Type>;
+        type TypeBuilder: TypeBuilder<'a, Self::Type>;
         /// create a new `Module`
         fn create_module(&self, name: &str) -> Self::Module;
         /// create a new `Builder`
@@ -283,3 +538,26 @@ pub mod backend {
         ) -> SCU::ReturnType;
     }
 }
+
+#[cfg(test)]
+mod test {
+    #![allow(dead_code)]
+
+    buildable_struct!{
+        struct S1 {
+        }
+    }
+
+    buildable_struct!{
+        pub struct S2 {
+            v: u32,
+        }
+    }
+
+    buildable_struct!{
+        struct S3 {
+            p: *mut S2,
+            v: ::backend::VecNx4<f32>,
+        }
+    }
+}