From 869a98f5b204b9743d337fddc64edf2dd4ae89f0 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 8 Oct 2018 21:08:46 -0700 Subject: [PATCH] working on shader compiler --- shader-compiler-llvm-7/src/backend.rs | 165 ++++++++++++++++- shader-compiler-llvm-7/src/lib.rs | 6 +- shader-compiler/src/lib.rs | 248 +++++++++++++++++++++++++- 3 files changed, 407 insertions(+), 12 deletions(-) diff --git a/shader-compiler-llvm-7/src/backend.rs b/shader-compiler-llvm-7/src/backend.rs index 2c24f81..d3c7437 100644 --- a/shader-compiler-llvm-7/src/backend.rs +++ b/shader-compiler-llvm-7/src/backend.rs @@ -2,35 +2,175 @@ // 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); -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) -> Self { + LLVM7String(v) + } + unsafe fn from_ptr(v: *mut c_char) -> Option { + 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(shader_compiler_user: SCU) -> SCU::ReturnType { - let context = unsafe { LLVM7Context(llvm_sys::core::LLVMContextCreate()) }; + fn run_with_user( + 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) } } diff --git a/shader-compiler-llvm-7/src/lib.rs b/shader-compiler-llvm-7/src/lib.rs index 70249dd..fad391e 100644 --- a/shader-compiler-llvm-7/src/lib.rs +++ b/shader-compiler-llvm-7/src/lib.rs @@ -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; diff --git a/shader-compiler/src/lib.rs b/shader-compiler/src/lib.rs index 446f3a0..b188709 100644 --- a/shader-compiler/src/lib.rs +++ b/shader-compiler/src/lib.rs @@ -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(&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 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 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 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(PhantomData<*const Element>); + + impl BuildableType for $name { + fn build<'a, TB: TypeBuilder<'a>>(type_builder: &TB) -> TB::Type { + type_builder.build_vector(Element::build(type_builder), Self::LENGTH) + } + } + + impl Vector for $name { + 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 = 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 }); + + /// 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(shader_compiler_user: SCU) -> SCU::ReturnType; + fn run_with_user( + shader_compiler_user: SCU, + config: Self::Config, + ) -> SCU::ReturnType; } } -- 2.30.2