working on shader compiler
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 9 Oct 2018 04:08:46 +0000 (21:08 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 9 Oct 2018 04:08:46 +0000 (21:08 -0700)
shader-compiler-llvm-7/src/backend.rs
shader-compiler-llvm-7/src/lib.rs
shader-compiler/src/lib.rs

index 2c24f81336569ff96bafb66a05422026f3593ebd..d3c743744e4d7ff4233df57b859e5209b353319c 100644 (file)
 // Copyright 2018 Jacob Lifshay
 use llvm_sys;
 use shader_compiler::backend::*;
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::ops::Deref;
 use std::os::raw::c_char;
+use std::ptr::NonNull;
+
+#[derive(Clone)]
+pub struct LLVM7ShaderCompilerConfig {
+    pub variable_vector_length_multiplier: u32,
+}
+
+impl Default for LLVM7ShaderCompilerConfig {
+    fn default() -> Self {
+        Self {
+            variable_vector_length_multiplier: 1,
+        }
+    }
+}
 
 #[repr(transparent)]
-pub struct LLVM7Context(llvm_sys::prelude::LLVMContextRef);
+struct LLVM7String(NonNull<c_char>);
 
-impl Drop for LLVM7Context {
+impl Drop for LLVM7String {
     fn drop(&mut self) {
         unsafe {
-            llvm_sys::core::LLVMContextDispose(self.0);
+            llvm_sys::core::LLVMDisposeMessage(self.0.as_ptr());
         }
     }
 }
 
-unsafe impl Send for LLVM7Context {}
+impl Deref for LLVM7String {
+    type Target = CStr;
+    fn deref(&self) -> &CStr {
+        unsafe { CStr::from_ptr(self.0.as_ptr()) }
+    }
+}
+
+impl Clone for LLVM7String {
+    fn clone(&self) -> Self {
+        Self::new(self)
+    }
+}
+
+impl LLVM7String {
+    fn new(v: &CStr) -> Self {
+        unsafe { Self::from_ptr(llvm_sys::core::LLVMCreateMessage(v.as_ptr())).unwrap() }
+    }
+    unsafe fn from_nonnull(v: NonNull<c_char>) -> Self {
+        LLVM7String(v)
+    }
+    unsafe fn from_ptr(v: *mut c_char) -> Option<Self> {
+        NonNull::new(v).map(LLVM7String)
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Hash)]
+#[repr(transparent)]
+pub struct LLVM7Type(llvm_sys::prelude::LLVMTypeRef);
+
+impl fmt::Debug for LLVM7Type {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        unsafe {
+            let string = LLVM7String::from_ptr(llvm_sys::core::LLVMPrintTypeToString(self.0))
+                .ok_or(fmt::Error)?;
+            f.write_str(&string.to_string_lossy())
+        }
+    }
+}
+
+impl<'a> Type<'a> for LLVM7Type {}
+
+pub struct LLVM7TypeBuilder {
+    context: llvm_sys::prelude::LLVMContextRef,
+    variable_vector_length_multiplier: u32,
+}
+
+impl<'a> TypeBuilder<'a> for LLVM7TypeBuilder {
+    type Type = LLVM7Type;
+    fn build_bool(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMInt1TypeInContext(self.context)) }
+    }
+    fn build_i8(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMInt8TypeInContext(self.context)) }
+    }
+    fn build_i16(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMInt16TypeInContext(self.context)) }
+    }
+    fn build_i32(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMInt32TypeInContext(self.context)) }
+    }
+    fn build_i64(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMInt64TypeInContext(self.context)) }
+    }
+    fn build_f32(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMFloatTypeInContext(self.context)) }
+    }
+    fn build_f64(&self) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMDoubleTypeInContext(self.context)) }
+    }
+    fn build_pointer(&self, target: LLVM7Type) -> LLVM7Type {
+        unsafe { LLVM7Type(llvm_sys::core::LLVMPointerType(target.0, 0)) }
+    }
+    fn build_array(&self, element: LLVM7Type, count: usize) -> LLVM7Type {
+        assert_eq!(count as u32 as usize, count);
+        unsafe { LLVM7Type(llvm_sys::core::LLVMArrayType(element.0, count as u32)) }
+    }
+    fn build_vector(&self, element: LLVM7Type, length: VectorLength) -> LLVM7Type {
+        let length = match length {
+            VectorLength::Fixed { length } => length,
+            VectorLength::Variable { base_length } => base_length
+                .checked_mul(self.variable_vector_length_multiplier)
+                .unwrap(),
+        };
+        assert_ne!(length, 0);
+        unsafe { LLVM7Type(llvm_sys::core::LLVMVectorType(element.0, length)) }
+    }
+}
+
+pub struct LLVM7Context {
+    context: llvm_sys::prelude::LLVMContextRef,
+    config: LLVM7ShaderCompilerConfig,
+}
+
+impl Drop for LLVM7Context {
+    fn drop(&mut self) {
+        unsafe {
+            llvm_sys::core::LLVMContextDispose(self.context);
+        }
+    }
+}
 
 impl<'a> Context<'a> for LLVM7Context {
+    type Type = LLVM7Type;
+    type TypeBuilder = LLVM7TypeBuilder;
     type Module = LLVM7Module;
+    type Builder = LLVM7Builder;
     fn create_module(&self, name: &str) -> LLVM7Module {
         let name = CString::new(name).unwrap();
         unsafe {
             LLVM7Module(llvm_sys::core::LLVMModuleCreateWithNameInContext(
                 name.as_ptr(),
-                self.0,
+                self.context,
             ))
         }
     }
+    fn create_builder(&self) -> LLVM7Builder {
+        unsafe { LLVM7Builder(llvm_sys::core::LLVMCreateBuilderInContext(self.context)) }
+    }
+    fn create_type_builder(&self) -> LLVM7TypeBuilder {
+        LLVM7TypeBuilder {
+            context: self.context,
+            variable_vector_length_multiplier: self.config.variable_vector_length_multiplier,
+        }
+    }
 }
 
+#[repr(transparent)]
+pub struct LLVM7Builder(llvm_sys::prelude::LLVMBuilderRef);
+
+impl Drop for LLVM7Builder {
+    fn drop(&mut self) {
+        unsafe {
+            llvm_sys::core::LLVMDisposeBuilder(self.0);
+        }
+    }
+}
+
+impl<'a> Builder<'a> for LLVM7Builder {}
+
 #[repr(transparent)]
 pub struct LLVM7Module(llvm_sys::prelude::LLVMModuleRef);
 
@@ -57,11 +197,20 @@ impl<'a> Module<'a> for LLVM7Module {
 pub struct LLVM7ShaderCompiler;
 
 impl ShaderCompiler for LLVM7ShaderCompiler {
+    type Config = LLVM7ShaderCompilerConfig;
     fn name() -> &'static str {
         "LLVM 7"
     }
-    fn run_with_user<SCU: ShaderCompilerUser>(shader_compiler_user: SCU) -> SCU::ReturnType {
-        let context = unsafe { LLVM7Context(llvm_sys::core::LLVMContextCreate()) };
+    fn run_with_user<SCU: ShaderCompilerUser>(
+        shader_compiler_user: SCU,
+        config: LLVM7ShaderCompilerConfig,
+    ) -> SCU::ReturnType {
+        let context = unsafe {
+            LLVM7Context {
+                context: llvm_sys::core::LLVMContextCreate(),
+                config,
+            }
+        };
         shader_compiler_user.run_with_context(&context)
     }
 }
index 70249dd945a7885fcd5122a4380c22034f19c15f..fad391e86cb14e69246b4b66992bc903e8630f92 100644 (file)
@@ -5,6 +5,6 @@ extern crate shader_compiler;
 
 mod backend;
 
-pub fn create_shader_compiler() -> backend::LLVM7ShaderCompiler {
-    backend::LLVM7ShaderCompiler
-}
+pub use backend::LLVM7ShaderCompilerConfig;
+
+pub const LLVM_7_SHADER_COMPILER: backend::LLVM7ShaderCompiler = backend::LLVM7ShaderCompiler;
index 446f3a05a77b5739c19ffa9551122462c1842fae..b18870956c55b67a690bbb442b031f456df2ffcd 100644 (file)
@@ -6,6 +6,237 @@
 
 /// Shader Compiler Backend traits
 pub mod backend {
+    use std::fmt::Debug;
+    use std::hash::Hash;
+    use std::marker::PhantomData;
+
+    /// 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 {}
+
+    /// trait for building types
+    pub trait TypeBuilder<'a>: Sized {
+        /// the `Type` type
+        type Type: Type<'a>;
+        /// build a `bool` type
+        fn build_bool(&self) -> Self::Type;
+        /// build an 8-bit sign-agnostic integer type
+        fn build_i8(&self) -> Self::Type;
+        /// build an 16-bit sign-agnostic integer type
+        fn build_i16(&self) -> Self::Type;
+        /// build an 32-bit sign-agnostic integer type
+        fn build_i32(&self) -> Self::Type;
+        /// build an 64-bit sign-agnostic integer type
+        fn build_i64(&self) -> Self::Type;
+        /// build an 32-bit IEEE 754 floating-point type
+        fn build_f32(&self) -> Self::Type;
+        /// build an 64-bit IEEE 754 floating-point type
+        fn build_f64(&self) -> Self::Type;
+        /// build a pointer
+        fn build_pointer(&self, target: Self::Type) -> Self::Type;
+        /// build an array
+        fn build_array(&self, element: Self::Type, count: usize) -> Self::Type;
+        /// build a vector
+        fn build_vector(&self, element: Self::Type, length: VectorLength) -> Self::Type;
+        /// build a type
+        fn build<T: BuildableType>(&self) -> Self::Type {
+            T::build(self)
+        }
+    }
+
+    /// 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;
+    }
+
+    /// trait for rust types that can be an element of a vector and be built using `TypeBuilder`
+    pub trait ScalarBuildableType: BuildableType {}
+
+    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 {
+                    type_builder.$build_fn()
+                }
+            }
+
+            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 &'b T {
+        fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+            type_builder.build_pointer(T::build(type_builder))
+        }
+    }
+
+    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 {
+            type_builder.build_pointer(T::build(type_builder))
+        }
+    }
+
+    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 {
+            type_builder.build_pointer(T::build(type_builder))
+        }
+    }
+
+    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 {
+            type_builder.build_pointer(T::build(type_builder))
+        }
+    }
+
+    impl<'b, T: BuildableType> ScalarBuildableType for *const T {}
+
+    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 {
+                    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;
+    }
+
+    macro_rules! build_vector {
+        ($name:ident, $length:expr) => {
+            /// Vector of elements `Element`
+            pub struct $name<Element: ScalarBuildableType>(PhantomData<*const Element>);
+
+            impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
+                fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type {
+                    type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
+                }
+            }
+
+            impl<Element: ScalarBuildableType> Vector for $name<Element> {
+                type Element = Element;
+                const LENGTH: VectorLength = {
+                    use self::VectorLength::*;
+                    $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 });
+
+    /// equivalent to LLVM's 'IRBuilder'
+    pub trait Builder<'a> {}
+
     /// equivalent to LLVM's 'Module'
     pub trait Module<'a> {
         /// set's the source file name for this module
@@ -16,8 +247,18 @@ pub mod backend {
     pub trait Context<'a> {
         /// the `Module` type
         type Module: Module<'a>;
+        /// the `Builder` type
+        type Builder: Builder<'a>;
+        /// the `Type` type
+        type Type: Type<'a>;
+        /// the `TypeBuilder` type
+        type TypeBuilder: TypeBuilder<'a, Type = Self::Type>;
         /// create a new `Module`
         fn create_module(&self, name: &str) -> Self::Module;
+        /// create a new `Builder`
+        fn create_builder(&self) -> Self::Builder;
+        /// create a new `TypeBuilder`
+        fn create_type_builder(&self) -> Self::TypeBuilder;
     }
 
     /// trait that the user of `ShaderCompiler` implements
@@ -30,10 +271,15 @@ pub mod backend {
 
     /// main shader compiler backend trait
     pub trait ShaderCompiler: Send + Sync + 'static {
+        /// the shader compiler's configuration
+        type Config: Default + Clone;
         /// get shader compiler's name
         fn name() -> &'static str;
         /// run a passed-in function with a new compiler context.
         /// this round-about method is used because generic associated types are not in stable Rust yet
-        fn run_with_user<SCU: ShaderCompilerUser>(shader_compiler_user: SCU) -> SCU::ReturnType;
+        fn run_with_user<SCU: ShaderCompilerUser>(
+            shader_compiler_user: SCU,
+            config: Self::Config,
+        ) -> SCU::ReturnType;
     }
 }