From 1fa95e2f8e2335eeaeaa5e43a56fcfc2999989c4 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 9 Oct 2018 02:21:50 -0700 Subject: [PATCH] completed shader compiler backend type system --- shader-compiler-llvm-7/src/backend.rs | 31 +- shader-compiler/src/lib.rs | 402 ++++++++++++++++++++++---- 2 files changed, 368 insertions(+), 65 deletions(-) diff --git a/shader-compiler-llvm-7/src/backend.rs b/shader-compiler-llvm-7/src/backend.rs index d3c7437..74af1b5 100644 --- a/shader-compiler-llvm-7/src/backend.rs +++ b/shader-compiler-llvm-7/src/backend.rs @@ -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 { + 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 { diff --git a/shader-compiler/src/lib.rs b/shader-compiler/src/lib.rs index b188709..fe2ab5d 100644 --- a/shader-compiler/src/lib.rs +++ b/shader-compiler/src/lib.rs @@ -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; /// build a type - fn build(&self) -> Self::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, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type; + 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 {} + 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, 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 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 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 { + 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 {} + }; + } + + 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> {} + }; + } + + 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, 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(PhantomData<*const 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, 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 Vector for $name { 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 = VecN; - 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 = 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); /// 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, + } + } +} -- 2.30.2