From: Jacob Lifshay Date: Fri, 19 Oct 2018 04:52:39 +0000 (-0700) Subject: split shader compiler backend into separate crate X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e1019257d1b05b93f2e55b59860fc62e12f746fd;p=kazan.git split shader compiler backend into separate crate --- diff --git a/Cargo.toml b/Cargo.toml index e4c4905..be9c384 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ # Copyright 2018 Jacob Lifshay [workspace] members = [ - "shader-compiler", - "shader-compiler-llvm-7", + "shader-compiler-backend", + "shader-compiler-backend-llvm-7", "vulkan-driver", ] diff --git a/shader-compiler-backend-llvm-7/Cargo.toml b/shader-compiler-backend-llvm-7/Cargo.toml new file mode 100644 index 0000000..323b2b8 --- /dev/null +++ b/shader-compiler-backend-llvm-7/Cargo.toml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2018 Jacob Lifshay +[package] +name = "shader-compiler-backend-llvm-7" +version = "0.1.0" +authors = ["Jacob Lifshay "] +license = "LGPL-2.1-or-later" + +[lib] +crate-type = ["rlib"] + +[dependencies] +shader-compiler-backend = {path = "../shader-compiler-backend"} + +[build-dependencies] +cmake = "0.1.35" +bindgen = "0.42" +tar = "0.4.17" +reqwest = "0.9" +xz2 = "0.1.6" +ring = "0.13" +cc = "1.0" +fs2 = "0.4.3" +which = "2.0.0" diff --git a/shader-compiler-backend-llvm-7/build.rs b/shader-compiler-backend-llvm-7/build.rs new file mode 100644 index 0000000..c45929b --- /dev/null +++ b/shader-compiler-backend-llvm-7/build.rs @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay + +// Partially based on llvm-sys; llvm-sys's license is reproduced below: + +// Copyright (c) 2015 Peter Marheine +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +extern crate bindgen; +extern crate cc; +extern crate cmake; +extern crate fs2; +extern crate reqwest; +extern crate ring; +extern crate tar; +extern crate which; +extern crate xz2; +use fs2::FileExt; +use std::env; +use std::ffi::OsStr; +use std::fs; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; +use std::process::Command; + +const LLVM_7_SOURCE_TAR_XZ_URL: &'static str = + "http://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz"; + +const LLVM_7_SOURCE_TAR_XZ_SHA256_HASH: &'static [u8; 32] = &[ + 0x8b, 0xc1, 0xf8, 0x44, 0xe6, 0xcb, 0xde, 0x1b, 0x65, 0x2c, 0x19, 0xc1, 0xed, 0xeb, 0xc1, 0x86, + 0x44, 0x56, 0xfd, 0x9c, 0x78, 0xb8, 0xc1, 0xbe, 0xa0, 0x38, 0xe5, 0x1b, 0x36, 0x3f, 0xe2, 0x22, +]; + +const LLVM_7_SOURCE_DIR_SUFFIX: &'static str = "llvm-7.0.0.src"; + +fn verify_sha256(mut f: fs::File, file_path: &Path) -> fs::File { + f.seek(io::SeekFrom::Start(0)).unwrap(); + let mut context = ring::digest::Context::new(&ring::digest::SHA256); + let mut buffer = [0; 1 << 12]; // 4KiB + loop { + let count = f.read(&mut buffer).unwrap(); + if count == 0 { + break; + } + context.update(&buffer[..count]); + } + let hash = context.finish(); + if hash.as_ref() != LLVM_7_SOURCE_TAR_XZ_SHA256_HASH { + panic!( + "file is corrupted: SHA256 doesn't match; try deleting {} and rerunning cargo", + file_path.display(), + ); + } + f.seek(io::SeekFrom::Start(0)).unwrap(); + f +} + +fn download_llvm_7(out_dir: &Path) -> io::Result { + let filename = LLVM_7_SOURCE_TAR_XZ_URL.rsplit('/').next().unwrap(); + let file_path = out_dir.join(filename); + match fs::File::open(&file_path) { + Ok(file) => return Ok(verify_sha256(file, &file_path)), + Err(ref error) if error.kind() == io::ErrorKind::NotFound => {} + Err(error) => return Err(error), + }; + let response = reqwest::get(LLVM_7_SOURCE_TAR_XZ_URL) + .map_err(|v| io::Error::new(io::ErrorKind::Other, v))?; + let file = fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&file_path)?; + { response } + .copy_to(&mut { file }) + .map_err(|v| io::Error::new(io::ErrorKind::Other, v))?; + Ok(verify_sha256(fs::File::open(&file_path)?, &file_path)) +} + +fn extract_tar_xz>(r: R, target_path: T) -> io::Result<()> { + tar::Archive::new(xz2::read::XzDecoder::new(r)).unpack(target_path) +} + +fn download_and_extract_llvm_7_if_needed(llvm_dir: &Path) -> io::Result { + let source_dir = llvm_dir.join(LLVM_7_SOURCE_DIR_SUFFIX); + match fs::File::open(source_dir.join("CMakeLists.txt")) { + Ok(_) => return Ok(source_dir), + Err(ref error) if error.kind() == io::ErrorKind::NotFound => {} + Err(error) => return Err(error), + } + extract_tar_xz(download_llvm_7(llvm_dir)?, llvm_dir)?; + Ok(source_dir) +} + +fn make_config(llvm_dir: &Path) -> cmake::Config { + let mut retval = cmake::Config::new(llvm_dir.join(LLVM_7_SOURCE_DIR_SUFFIX)); + let found_ccache = match which::which("ccache") { + Err(ref error) if error.kind() == which::ErrorKind::CannotFindBinaryPath => false, + result => { + result.unwrap(); + true + } + }; + retval + .generator("Ninja") + .define("LLVM_TARGETS_TO_BUILD", "host") + .define("LLVM_CCACHE_BUILD", if found_ccache { "ON" } else { "OFF" }) + .define( + "LLVM_TARGET_ARCH", + env::var("TARGET").unwrap().split("-").next().unwrap(), + ) + .out_dir(llvm_dir) + .profile("Debug") + .always_configure(false); + retval +} + +fn llvm_config, S: AsRef>( + llvm_config_path: &Path, + args: A, +) -> String { + String::from_utf8( + Command::new(llvm_config_path) + .arg("--link-static") + .args(args) + .output() + .unwrap() + .stdout, + ) + .unwrap() +} + +fn get_libs, S: AsRef>( + llvm_config_path: &Path, + args: A, +) -> Vec { + llvm_config(llvm_config_path, args) + .split_whitespace() + .chain(llvm_config(llvm_config_path, Some("--system-libs")).split_whitespace()) + .filter_map(|flag| { + if flag == "" { + None + } else if cfg!(target_env = "msvc") { + // Same as --libnames, foo.lib + assert!(flag.ends_with(".lib")); + Some(&flag[..flag.len() - 4]) + } else { + // Linker flags style, -lfoo + assert!(flag.starts_with("-l")); + Some(&flag[2..]) + } + }) + .map(Into::into) + .collect() +} + +struct LockedFile(fs::File); + +impl Drop for LockedFile { + fn drop(&mut self) { + let _ = self.0.unlock(); + } +} + +impl LockedFile { + fn new>(file_path: T) -> io::Result { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(file_path)?; + file.lock_exclusive()?; + Ok(LockedFile(file)) + } +} + +fn build_llvm() -> PathBuf { + assert_eq!( + env::var_os("TARGET"), + env::var_os("HOST"), + "cross-compilation is not supported" + ); + let llvm_dir = env::current_dir() + .unwrap() + .join("..") + .join("external") + .join("llvm-7") + .join(env::var_os("TARGET").unwrap()); + fs::create_dir_all(&llvm_dir).unwrap(); + let _locked_file = LockedFile::new(llvm_dir.join(".build-lock")).unwrap(); + download_and_extract_llvm_7_if_needed(&llvm_dir).unwrap(); + make_config(&llvm_dir).build_target("install").build(); + #[cfg(windows)] + let llvm_config_path = llvm_dir.join("bin").join("llvm-config.exe"); + #[cfg(not(windows))] + let llvm_config_path = llvm_dir.join("bin").join("llvm-config"); + llvm_config_path +} + +fn main() { + let out_dir = Path::new(&env::var_os("OUT_DIR").unwrap()).to_path_buf(); + let llvm_config_path = build_llvm(); + println!( + "cargo:rustc-link-search=native={}", + llvm_config(&llvm_config_path, Some("--libdir")) + ); + let llvm_libs = get_libs( + &llvm_config_path, + &["--libs", "orcjit", "native", "analysis"], + ); + let header = r#" +#include "llvm-c/Core.h" +#include "llvm-c/OrcBindings.h" +#include "llvm-c/Target.h" +#include "llvm-c/Analysis.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +void LLVM_InitializeNativeTarget(void); +void LLVM_InitializeNativeAsmParser(void); +void LLVM_InitializeNativeAsmPrinter(void); +void LLVM_InitializeNativeDisassembler(void); + +#ifdef __cplusplus +} +#endif +"#; + let header_path = out_dir.join("llvm_bindings.h"); + fs::write(&header_path, header).unwrap(); + let llvm_bindings_source = format!("#include {:?}\n", header_path) + r#" +void LLVM_InitializeNativeTarget(void) +{ + LLVM_NATIVE_TARGETINFO(); + LLVM_NATIVE_TARGET(); + LLVM_NATIVE_TARGETMC(); +} + +void LLVM_InitializeNativeAsmParser(void) +{ + LLVM_NATIVE_ASMPARSER(); +} + +void LLVM_InitializeNativeAsmPrinter(void) +{ + LLVM_NATIVE_ASMPRINTER(); +} + +void LLVM_InitializeNativeDisassembler(void) +{ + LLVM_NATIVE_DISASSEMBLER(); +} +"#; + let llvm_bindings_path = out_dir.join("llvm_bindings.c"); + fs::write(&llvm_bindings_path, llvm_bindings_source).unwrap(); + let include_dir: String = llvm_config(&llvm_config_path, Some("--includedir")) + .trim_right() + .into(); + let builder = bindgen::Builder::default() + .header(header_path.to_str().unwrap()) + .clang_arg("-I") + .clang_arg(&include_dir as &str) + .rustfmt_bindings(true) + .whitelist_type("LLVM.*") + .whitelist_function("LLVM.*") + .whitelist_var("LLVM.*") + .blacklist_type("^__.*") + .prepend_enum_name(false) + .constified_enum("LLVM.*"); + builder + .generate() + .unwrap() + .write_to_file(out_dir.join("llvm_c.rs")) + .unwrap(); + let build_llvm_bindings = || { + let mut retval = cc::Build::new(); + retval + .cpp(true) + .file(&llvm_bindings_path) + .include(&include_dir); + retval + }; + build_llvm_bindings() + .cpp_link_stdlib(None) + .compile("llvm_bindings"); + for lib in llvm_libs { + println!("cargo:rustc-link-lib={}", lib); + } + // build twice to get the c++ standard library linked after LLVM with llvm_bindings before LLVM + build_llvm_bindings().compile("llvm_bindings"); +} diff --git a/shader-compiler-backend-llvm-7/src/backend.rs b/shader-compiler-backend-llvm-7/src/backend.rs new file mode 100644 index 0000000..95bfa5a --- /dev/null +++ b/shader-compiler-backend-llvm-7/src/backend.rs @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay +use llvm; +use shader_compiler_backend as backend; +use std::cell::RefCell; +use std::collections::HashMap; +use std::collections::HashSet; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::hash::Hash; +use std::mem; +use std::mem::ManuallyDrop; +use std::ops::Deref; +use std::os::raw::{c_char, c_uint}; +use std::ptr::null_mut; +use std::ptr::NonNull; +use std::sync::{Once, ONCE_INIT}; + +fn to_bool(v: llvm::LLVMBool) -> bool { + v != 0 +} + +#[derive(Clone)] +pub struct LLVM7CompilerConfig { + pub variable_vector_length_multiplier: u32, + pub optimization_mode: backend::OptimizationMode, +} + +impl Default for LLVM7CompilerConfig { + fn default() -> Self { + backend::CompilerIndependentConfig::default().into() + } +} + +impl From for LLVM7CompilerConfig { + fn from(v: backend::CompilerIndependentConfig) -> Self { + let backend::CompilerIndependentConfig { optimization_mode } = v; + Self { + variable_vector_length_multiplier: 1, + optimization_mode, + } + } +} + +#[repr(transparent)] +struct LLVM7String(NonNull); + +impl Drop for LLVM7String { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeMessage(self.0.as_ptr()); + } + } +} + +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::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(|v| Self::from_nonnull(v)) + } +} + +impl fmt::Debug for LLVM7String { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} + +#[derive(Clone, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct LLVM7Type(llvm::LLVMTypeRef); + +impl fmt::Debug for LLVM7Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string = + LLVM7String::from_ptr(llvm::LLVMPrintTypeToString(self.0)).ok_or(fmt::Error)?; + f.write_str(&string.to_string_lossy()) + } + } +} + +impl<'a> backend::types::Type<'a> for LLVM7Type { + type Context = LLVM7Context; +} + +pub struct LLVM7TypeBuilder { + context: llvm::LLVMContextRef, + variable_vector_length_multiplier: u32, +} + +impl<'a> backend::types::TypeBuilder<'a, LLVM7Type> for LLVM7TypeBuilder { + fn build_bool(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMInt1TypeInContext(self.context)) } + } + fn build_i8(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMInt8TypeInContext(self.context)) } + } + fn build_i16(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMInt16TypeInContext(self.context)) } + } + fn build_i32(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMInt32TypeInContext(self.context)) } + } + fn build_i64(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMInt64TypeInContext(self.context)) } + } + fn build_f32(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMFloatTypeInContext(self.context)) } + } + fn build_f64(&self) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMDoubleTypeInContext(self.context)) } + } + fn build_pointer(&self, target: LLVM7Type) -> LLVM7Type { + unsafe { LLVM7Type(llvm::LLVMPointerType(target.0, 0)) } + } + fn build_array(&self, element: LLVM7Type, count: usize) -> LLVM7Type { + assert_eq!(count as u32 as usize, count); + unsafe { LLVM7Type(llvm::LLVMArrayType(element.0, count as u32)) } + } + fn build_vector(&self, element: LLVM7Type, length: backend::types::VectorLength) -> LLVM7Type { + use self::backend::types::VectorLength::*; + let length = match length { + Fixed { length } => length, + Variable { base_length } => base_length + .checked_mul(self.variable_vector_length_multiplier) + .unwrap(), + }; + assert_ne!(length, 0); + unsafe { LLVM7Type(llvm::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::LLVMStructTypeInContext( + self.context, + members.as_ptr() as *mut llvm::LLVMTypeRef, + members.len() as c_uint, + false as llvm::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::LLVMFunctionType( + return_type + .unwrap_or_else(|| LLVM7Type(llvm::LLVMVoidTypeInContext(self.context))) + .0, + arguments.as_ptr() as *mut llvm::LLVMTypeRef, + arguments.len() as c_uint, + false as llvm::LLVMBool, + )) + } + } +} + +#[derive(Clone)] +#[repr(transparent)] +pub struct LLVM7Value(llvm::LLVMValueRef); + +impl fmt::Debug for LLVM7Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string = + LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.0)).ok_or(fmt::Error)?; + f.write_str(&string.to_string_lossy()) + } + } +} + +impl<'a> backend::Value<'a> for LLVM7Value { + type Context = LLVM7Context; +} + +#[derive(Clone)] +#[repr(transparent)] +pub struct LLVM7BasicBlock(llvm::LLVMBasicBlockRef); + +impl fmt::Debug for LLVM7BasicBlock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::backend::BasicBlock; + unsafe { + let string = LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.as_value().0)) + .ok_or(fmt::Error)?; + f.write_str(&string.to_string_lossy()) + } + } +} + +impl<'a> backend::BasicBlock<'a> for LLVM7BasicBlock { + type Context = LLVM7Context; + fn as_value(&self) -> LLVM7Value { + unsafe { LLVM7Value(llvm::LLVMBasicBlockAsValue(self.0)) } + } +} + +impl<'a> backend::BuildableBasicBlock<'a> for LLVM7BasicBlock { + type Context = LLVM7Context; + fn as_basic_block(&self) -> LLVM7BasicBlock { + self.clone() + } +} + +pub struct LLVM7Function { + context: llvm::LLVMContextRef, + function: llvm::LLVMValueRef, + parameters: Box<[LLVM7Value]>, +} + +impl fmt::Debug for LLVM7Function { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string = LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.function)) + .ok_or(fmt::Error)?; + f.write_str(&string.to_string_lossy()) + } + } +} + +impl<'a> backend::Function<'a> for LLVM7Function { + type Context = LLVM7Context; + fn as_value(&self) -> LLVM7Value { + LLVM7Value(self.function) + } + fn append_new_basic_block(&mut self, name: Option<&str>) -> LLVM7BasicBlock { + let name = CString::new(name.unwrap_or("")).unwrap(); + unsafe { + LLVM7BasicBlock(llvm::LLVMAppendBasicBlockInContext( + self.context, + self.function, + name.as_ptr(), + )) + } + } + fn parameters(&self) -> &[LLVM7Value] { + &self.parameters + } +} + +pub struct LLVM7Context { + context: Option>, + modules: ManuallyDrop>>, + config: LLVM7CompilerConfig, +} + +impl Drop for LLVM7Context { + fn drop(&mut self) { + unsafe { + ManuallyDrop::drop(&mut self.modules); + if let Some(context) = &mut self.context { + ManuallyDrop::drop(context); + } + } + } +} + +impl<'a> backend::Context<'a> for LLVM7Context { + type Value = LLVM7Value; + type BasicBlock = LLVM7BasicBlock; + type BuildableBasicBlock = LLVM7BasicBlock; + type Function = LLVM7Function; + type Type = LLVM7Type; + type TypeBuilder = LLVM7TypeBuilder; + type Module = LLVM7Module; + type VerifiedModule = LLVM7Module; + type AttachedBuilder = LLVM7Builder; + type DetachedBuilder = LLVM7Builder; + fn create_module(&self, name: &str) -> LLVM7Module { + let name = CString::new(name).unwrap(); + let mut modules = self.modules.borrow_mut(); + unsafe { + let module = OwnedModule(llvm::LLVMModuleCreateWithNameInContext( + name.as_ptr(), + self.context.as_ref().unwrap().0, + )); + let module_ref = module.0; + modules.push(module); + LLVM7Module { + context: self.context.as_ref().unwrap().0, + module: module_ref, + name_set: HashSet::new(), + } + } + } + fn create_builder(&self) -> LLVM7Builder { + unsafe { + LLVM7Builder(llvm::LLVMCreateBuilderInContext( + self.context.as_ref().unwrap().0, + )) + } + } + fn create_type_builder(&self) -> LLVM7TypeBuilder { + LLVM7TypeBuilder { + context: self.context.as_ref().unwrap().0, + variable_vector_length_multiplier: self.config.variable_vector_length_multiplier, + } + } +} + +#[repr(transparent)] +pub struct LLVM7Builder(llvm::LLVMBuilderRef); + +impl Drop for LLVM7Builder { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeBuilder(self.0); + } + } +} + +impl<'a> backend::AttachedBuilder<'a> for LLVM7Builder { + type Context = LLVM7Context; + fn current_basic_block(&self) -> LLVM7BasicBlock { + unsafe { LLVM7BasicBlock(llvm::LLVMGetInsertBlock(self.0)) } + } + fn build_return(self, value: Option) -> LLVM7Builder { + unsafe { + match value { + Some(value) => llvm::LLVMBuildRet(self.0, value.0), + None => llvm::LLVMBuildRetVoid(self.0), + }; + llvm::LLVMClearInsertionPosition(self.0); + } + self + } +} + +impl<'a> backend::DetachedBuilder<'a> for LLVM7Builder { + type Context = LLVM7Context; + fn attach(self, basic_block: LLVM7BasicBlock) -> LLVM7Builder { + unsafe { + llvm::LLVMPositionBuilderAtEnd(self.0, basic_block.0); + } + self + } +} + +struct OwnedModule(llvm::LLVMModuleRef); + +impl Drop for OwnedModule { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeModule(self.0); + } + } +} + +impl OwnedModule { + unsafe fn take(mut self) -> llvm::LLVMModuleRef { + let retval = self.0; + self.0 = null_mut(); + retval + } +} + +struct OwnedContext(llvm::LLVMContextRef); + +impl Drop for OwnedContext { + fn drop(&mut self) { + unsafe { + llvm::LLVMContextDispose(self.0); + } + } +} + +pub struct LLVM7Module { + context: llvm::LLVMContextRef, + module: llvm::LLVMModuleRef, + name_set: HashSet, +} + +impl fmt::Debug for LLVM7Module { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string = LLVM7String::from_ptr(llvm::LLVMPrintModuleToString(self.module)) + .ok_or(fmt::Error)?; + f.write_str(&string.to_string_lossy()) + } + } +} + +impl<'a> backend::Module<'a> for LLVM7Module { + type Context = LLVM7Context; + fn set_source_file_name(&mut self, source_file_name: &str) { + unsafe { + llvm::LLVMSetSourceFileName( + self.module, + source_file_name.as_ptr() as *const c_char, + source_file_name.len(), + ) + } + } + fn add_function(&mut self, name: &str, ty: LLVM7Type) -> LLVM7Function { + fn is_start_char(c: char) -> bool { + if c.is_ascii_alphabetic() { + true + } else { + match c { + '_' | '.' | '$' | '-' => true, + _ => false, + } + } + } + fn is_continue_char(c: char) -> bool { + is_start_char(c) || c.is_ascii_digit() + } + assert!(is_start_char(name.chars().next().unwrap())); + assert!(name.chars().all(is_continue_char)); + assert!(self.name_set.insert(name.into())); + let name = CString::new(name).unwrap(); + unsafe { + let function = llvm::LLVMAddFunction(self.module, name.as_ptr(), ty.0); + let mut parameters = Vec::new(); + parameters.resize(llvm::LLVMCountParams(function) as usize, null_mut()); + llvm::LLVMGetParams(function, parameters.as_mut_ptr()); + let parameters: Vec<_> = parameters.into_iter().map(LLVM7Value).collect(); + LLVM7Function { + context: self.context, + function: llvm::LLVMAddFunction(self.module, name.as_ptr(), ty.0), + parameters: parameters.into_boxed_slice(), + } + } + } + fn verify(self) -> Result> { + unsafe { + let mut message = null_mut(); + let broken = to_bool(llvm::LLVMVerifyModule( + self.module, + llvm::LLVMReturnStatusAction, + &mut message, + )); + if broken { + let message = LLVM7String::from_ptr(message).unwrap(); + let message = message.to_string_lossy(); + Err(backend::VerificationFailure::new(self, message.as_ref())) + } else { + Ok(self) + } + } + } + unsafe fn to_verified_module_unchecked(self) -> LLVM7Module { + self + } +} + +impl<'a> backend::VerifiedModule<'a> for LLVM7Module { + type Context = LLVM7Context; + fn into_module(self) -> LLVM7Module { + self + } +} + +struct LLVM7TargetMachine(llvm::LLVMTargetMachineRef); + +impl Drop for LLVM7TargetMachine { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeTargetMachine(self.0); + } + } +} + +impl LLVM7TargetMachine { + fn take(mut self) -> llvm::LLVMTargetMachineRef { + let retval = self.0; + self.0 = null_mut(); + retval + } +} + +struct LLVM7OrcJITStack(llvm::LLVMOrcJITStackRef); + +impl Drop for LLVM7OrcJITStack { + fn drop(&mut self) { + unsafe { + match llvm::LLVMOrcDisposeInstance(self.0) { + llvm::LLVMOrcErrSuccess => {} + _ => { + panic!("LLVMOrcDisposeInstance failed"); + } + } + } + } +} + +fn initialize_native_target() { + static ONCE: Once = ONCE_INIT; + ONCE.call_once(|| unsafe { + llvm::LLVM_InitializeNativeTarget(); + llvm::LLVM_InitializeNativeAsmPrinter(); + llvm::LLVM_InitializeNativeAsmParser(); + }); +} + +extern "C" fn symbol_resolver_fn(name: *const c_char, _lookup_context: *mut Void) -> u64 { + let name = unsafe { CStr::from_ptr(name) }; + panic!("symbol_resolver_fn is unimplemented: name = {:?}", name) +} + +#[derive(Copy, Clone)] +pub struct LLVM7Compiler; + +impl backend::Compiler for LLVM7Compiler { + type Config = LLVM7CompilerConfig; + fn name(self) -> &'static str { + "LLVM 7" + } + fn run( + self, + user: U, + config: LLVM7CompilerConfig, + ) -> Result>, U::Error> { + unsafe { + initialize_native_target(); + let context = OwnedContext(llvm::LLVMContextCreate()); + let modules = Vec::new(); + let mut context = LLVM7Context { + context: Some(ManuallyDrop::new(context)), + modules: ManuallyDrop::new(RefCell::new(modules)), + config: config.clone(), + }; + let backend::CompileInputs { + module, + callable_functions, + } = user.run(&context)?; + let callable_functions: Vec<_> = callable_functions + .into_iter() + .map(|(key, callable_function)| { + assert_eq!( + llvm::LLVMGetGlobalParent(callable_function.function), + module.module + ); + let name: CString = + CStr::from_ptr(llvm::LLVMGetValueName(callable_function.function)).into(); + assert_ne!(name.to_bytes().len(), 0); + (key, name) + }) + .collect(); + let module = context + .modules + .get_mut() + .drain(..) + .find(|v| v.0 == module.module) + .unwrap(); + let target_triple = LLVM7String::from_ptr(llvm::LLVMGetDefaultTargetTriple()).unwrap(); + let mut target = null_mut(); + let mut error = null_mut(); + let success = !to_bool(llvm::LLVMGetTargetFromTriple( + target_triple.as_ptr(), + &mut target, + &mut error, + )); + if !success { + let error = LLVM7String::from_ptr(error).unwrap(); + return Err(U::create_error(error.to_string_lossy().into())); + } + if !to_bool(llvm::LLVMTargetHasJIT(target)) { + return Err(U::create_error(format!( + "target {:?} doesn't support JIT", + target_triple + ))); + } + let host_cpu_name = LLVM7String::from_ptr(llvm::LLVMGetHostCPUName()).unwrap(); + let host_cpu_features = LLVM7String::from_ptr(llvm::LLVMGetHostCPUFeatures()).unwrap(); + let target_machine = LLVM7TargetMachine(llvm::LLVMCreateTargetMachine( + target, + target_triple.as_ptr(), + host_cpu_name.as_ptr(), + host_cpu_features.as_ptr(), + match config.optimization_mode { + backend::OptimizationMode::NoOptimizations => llvm::LLVMCodeGenLevelNone, + backend::OptimizationMode::Normal => llvm::LLVMCodeGenLevelDefault, + }, + llvm::LLVMRelocDefault, + llvm::LLVMCodeModelJITDefault, + )); + assert!(!target_machine.0.is_null()); + let orc_jit_stack = + LLVM7OrcJITStack(llvm::LLVMOrcCreateInstance(target_machine.take())); + let mut module_handle = 0; + if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcAddEagerlyCompiledIR( + orc_jit_stack.0, + &mut module_handle, + module.take(), + Some(symbol_resolver_fn), + null_mut(), + ) { + return Err(U::create_error("compilation failed".into())); + } + let mut functions: HashMap<_, _> = HashMap::new(); + for (key, name) in callable_functions { + let mut address: llvm::LLVMOrcTargetAddress = mem::zeroed(); + if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcGetSymbolAddressIn( + orc_jit_stack.0, + &mut address, + module_handle, + name.as_ptr(), + ) { + return Err(U::create_error(format!( + "function not found in compiled module: {:?}", + name + ))); + } + let address: Option = mem::transmute(address as usize); + if functions.insert(key, address.unwrap()).is_some() { + return Err(U::create_error(format!("duplicate function: {:?}", name))); + } + } + struct CompiledCode { + functions: HashMap, + orc_jit_stack: ManuallyDrop, + context: ManuallyDrop, + } + unsafe impl Send for CompiledCode {} + unsafe impl Sync for CompiledCode {} + impl Drop for CompiledCode { + fn drop(&mut self) { + unsafe { + ManuallyDrop::drop(&mut self.orc_jit_stack); + ManuallyDrop::drop(&mut self.context); + } + } + } + impl backend::CompiledCode for CompiledCode { + fn get(&self, key: &K) -> Option { + Some(*self.functions.get(key)?) + } + } + Ok(Box::new(CompiledCode { + functions, + orc_jit_stack: ManuallyDrop::new(orc_jit_stack), + context: context.context.take().unwrap(), + })) + } + } +} diff --git a/shader-compiler-backend-llvm-7/src/lib.rs b/shader-compiler-backend-llvm-7/src/lib.rs new file mode 100644 index 0000000..c840645 --- /dev/null +++ b/shader-compiler-backend-llvm-7/src/lib.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay +extern crate shader_compiler_backend; + +#[cfg_attr( + feature = "cargo-clippy", + allow(clippy::const_static_lifetime) +)] +#[allow(dead_code)] +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +mod llvm { + include!(concat!(env!("OUT_DIR"), "/llvm_c.rs")); +} + +mod backend; +mod tests; + +pub use backend::LLVM7CompilerConfig; + +pub const LLVM_7_SHADER_COMPILER: backend::LLVM7Compiler = backend::LLVM7Compiler; diff --git a/shader-compiler-backend-llvm-7/src/tests.rs b/shader-compiler-backend-llvm-7/src/tests.rs new file mode 100644 index 0000000..a679e71 --- /dev/null +++ b/shader-compiler-backend-llvm-7/src/tests.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay +#[cfg(test)] +// we have a tests module inside a tests module to have rls parse this tests.rs file +#[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] +mod tests { + use shader_compiler_backend::types::TypeBuilder; + use shader_compiler_backend::*; + use std::mem; + + fn make_compiler() -> impl Compiler { + ::LLVM_7_SHADER_COMPILER + } + + #[test] + fn test_basic() { + type GeneratedFunctionType = unsafe extern "C" fn(u32); + #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] + enum FunctionKey { + Function, + } + struct Test; + impl CompilerUser for Test { + type FunctionKey = FunctionKey; + type Error = String; + fn create_error(message: String) -> String { + message + } + fn run<'a, C: Context<'a>>( + self, + context: &'a C, + ) -> Result, String> { + let type_builder = context.create_type_builder(); + let mut module = context.create_module("test_module"); + let mut function = module.add_function( + "test_function", + type_builder.build::(), + ); + let builder = context.create_builder(); + let builder = builder.attach(function.append_new_basic_block(None)); + builder.build_return(None); + let module = module.verify().unwrap(); + Ok(CompileInputs { + module, + callable_functions: vec![(FunctionKey::Function, function)] + .into_iter() + .collect(), + }) + } + } + let compiled_code = make_compiler().run(Test, Default::default()).unwrap(); + let function = compiled_code.get(&FunctionKey::Function).unwrap(); + unsafe { + let function: GeneratedFunctionType = mem::transmute(function); + function(0); + } + } + + #[test] + fn test_names() { + const NAMES: &[&str] = &["main", "abc123-$._"]; + type GeneratedFunctionType = unsafe extern "C" fn(u32); + #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] + struct Test; + impl CompilerUser for Test { + type FunctionKey = String; + type Error = String; + fn create_error(message: String) -> String { + message + } + fn run<'a, C: Context<'a>>( + self, + context: &'a C, + ) -> Result, String> { + let type_builder = context.create_type_builder(); + let mut module = context.create_module("test_module"); + let mut functions = Vec::new(); + let mut detached_builder = context.create_builder(); + for name in NAMES { + let mut function = + module.add_function(name, type_builder.build::()); + let builder = detached_builder.attach(function.append_new_basic_block(None)); + detached_builder = builder.build_return(None); + functions.push((name.to_string(), function)); + } + let module = module.verify().unwrap(); + Ok(CompileInputs { + module, + callable_functions: functions.into_iter().collect(), + }) + } + } + let compiled_code = make_compiler().run(Test, Default::default()).unwrap(); + let function = compiled_code.get(&"main".to_string()).unwrap(); + unsafe { + let function: GeneratedFunctionType = mem::transmute(function); + function(0); + } + } +} diff --git a/shader-compiler-backend/Cargo.toml b/shader-compiler-backend/Cargo.toml new file mode 100644 index 0000000..ec8fc80 --- /dev/null +++ b/shader-compiler-backend/Cargo.toml @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2018 Jacob Lifshay +[package] +name = "shader-compiler-backend" +version = "0.1.0" +authors = ["Jacob Lifshay "] +license = "LGPL-2.1-or-later" + +[lib] +crate-type = ["rlib"] + +[dependencies] diff --git a/shader-compiler-backend/src/lib.rs b/shader-compiler-backend/src/lib.rs new file mode 100644 index 0000000..0c3e1c3 --- /dev/null +++ b/shader-compiler-backend/src/lib.rs @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay +#![deny(missing_docs)] + +//! Shader Compiler Backend Traits for Kazan + +use std::collections::HashMap; +use std::error::Error; +use std::fmt; +use std::fmt::Debug; +use std::hash::Hash; +use std::io; +use std::marker::PhantomData; + +#[macro_use] +pub mod types; + +/// equivalent to LLVM's 'IRBuilder' +pub trait AttachedBuilder<'a>: Sized { + /// the `Context` type + type Context: Context<'a>; + /// get the current `BasicBlock` + fn current_basic_block(&self) -> >::BasicBlock; + /// build a return instruction + fn build_return( + self, + value: Option<>::Value>, + ) -> >::DetachedBuilder; +} + +/// equivalent to LLVM's 'IRBuilder' +pub trait DetachedBuilder<'a>: Sized { + /// the `Context` type + type Context: Context<'a>; + /// attach `basic_block` to `Self`, converting into an `AttachedBuilder` + fn attach( + self, + basic_block: >::BuildableBasicBlock, + ) -> >::AttachedBuilder; +} + +/// equivalent to LLVM's 'Value' +pub trait Value<'a>: Clone + Debug { + /// the `Context` type + type Context: Context<'a>; +} + +/// equivalent to LLVM's 'BasicBlock' +pub trait BasicBlock<'a>: Clone + Debug { + /// the `Context` type + type Context: Context<'a>; + /// get the `Value` corresponding to `Self` + fn as_value(&self) -> >::Value; +} + +/// equivalent to LLVM's 'BasicBlock' +pub trait BuildableBasicBlock<'a>: Debug + Sized { + /// the `Context` type + type Context: Context<'a>; + /// get the `BasicBlock` corresponding to `Self` + fn as_basic_block(&self) -> >::BasicBlock; + /// get the `Value` corresponding to `Self` + fn as_value(&self) -> >::Value { + self.as_basic_block().as_value() + } +} + +/// equivalent to LLVM's 'Function' +pub trait Function<'a>: Debug + Sized { + /// the `Context` type + type Context: Context<'a>; + /// get the `Value` corresponding to `Self` + fn as_value(&self) -> >::Value; + /// append a new `BasicBlock` to `Self` + fn append_new_basic_block( + &mut self, + name: Option<&str>, + ) -> >::BuildableBasicBlock; + /// get this function's parameters + fn parameters(&self) -> &[>::Value]; +} + +/// module verification failure; returned from `Module::verify` +pub struct VerificationFailure<'a, M: Module<'a>> { + module: M, + message: String, + _phantom_data: PhantomData<&'a ()>, +} + +impl<'a, M: Module<'a>> VerificationFailure<'a, M> { + /// create a new `VerificationFailure` + pub fn new(module: M, message: &T) -> Self { + VerificationFailure { + module, + message: message.to_string(), + _phantom_data: PhantomData, + } + } + /// get the `Module` that failed verification + pub fn into_module(self) -> M { + self.module + } +} + +impl<'a, M: Module<'a>> fmt::Display for VerificationFailure<'a, M> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "module verification failure: {}", self.message,) + } +} + +impl<'a, M: Module<'a>> Debug for VerificationFailure<'a, M> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("VerificationFailure") + .field("message", &self.message) + .field("module", &self.module) + .finish() + } +} + +impl<'a, M: Module<'a>> Error for VerificationFailure<'a, M> {} + +impl<'a, M: Module<'a>> From> for io::Error { + fn from(v: VerificationFailure<'a, M>) -> Self { + io::Error::new(io::ErrorKind::Other, format!("{}", v)) + } +} + +/// equivalent to LLVM's 'Module' +pub trait Module<'a>: Debug + Sized { + /// the `Context` type + type Context: Context<'a>; + /// set's the source file name for this module + fn set_source_file_name(&mut self, source_file_name: &str); + /// add a new empty function to `Self` + fn add_function( + &mut self, + name: &str, + ty: >::Type, + ) -> >::Function; + /// verify `Self`, converting into a `VerifiedModule` + fn verify( + self, + ) -> Result<>::VerifiedModule, VerificationFailure<'a, Self>>; + /// convert into a `VerifiedModule` without verifing + unsafe fn to_verified_module_unchecked(self) -> >::VerifiedModule; +} + +/// equivalent to LLVM's 'Module'; create using `Module::verify` or `Module::to_verified_module_unchecked` +pub trait VerifiedModule<'a>: Debug + Sized { + /// the `Context` type + type Context: Context<'a>; + /// convert back to an unverified module + fn into_module(self) -> >::Module; +} + +/// instance of a compiler backend; equivalent to LLVM's `LLVMContext` +pub trait Context<'a>: Sized { + /// the `Value` type + type Value: Value<'a, Context = Self>; + /// the `BasicBlock` type + type BasicBlock: BasicBlock<'a, Context = Self>; + /// the `BuildableBasicBlock` type + type BuildableBasicBlock: BuildableBasicBlock<'a, Context = Self>; + /// the `Function` type + type Function: Function<'a, Context = Self>; + /// the `Module` type + type Module: Module<'a, Context = Self>; + /// the `VerifiedModule` type + type VerifiedModule: VerifiedModule<'a, Context = Self>; + /// the `AttachedBuilder` type + type AttachedBuilder: AttachedBuilder<'a, Context = Self>; + /// the `DetachedBuilder` type + type DetachedBuilder: DetachedBuilder<'a, Context = Self>; + /// the `Type` type + type Type: types::Type<'a, Context = Self>; + /// the `TypeBuilder` type + type TypeBuilder: types::TypeBuilder<'a, Self::Type>; + /// create a new `Module` + fn create_module(&self, name: &str) -> Self::Module; + /// create a new `DetachedBuilder` + fn create_builder(&self) -> Self::DetachedBuilder; + /// create a new `TypeBuilder` + fn create_type_builder(&self) -> Self::TypeBuilder; +} + +/// inputs to the final compilation +pub struct CompileInputs<'a, C: Context<'a>, K: Hash + Eq + Send + Sync + 'static> { + /// the input module + pub module: C::VerifiedModule, + /// the list of functions that can be called from the final `CompiledCode` + pub callable_functions: HashMap, +} + +/// the final compiled code +pub trait CompiledCode: Send + Sync { + /// get a function in the final compiled code. + /// the returned function needs to be cast to the correct type and + /// `Self` needs to still exist while the returned function exists + fn get(&self, which: &K) -> Option; +} + +/// trait that the user of `Compiler` implements +pub trait CompilerUser { + /// the type used as a key for visible functions + type FunctionKey: Hash + Eq + Send + Sync + 'static; + /// the user's error type + type Error; + /// create an instance of `Error` + fn create_error(message: String) -> Self::Error; + /// the function that the user of `Compiler` implements + fn run<'a, C: Context<'a>>( + self, + context: &'a C, + ) -> Result, Self::Error>; +} + +/// optimization mode +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum OptimizationMode { + /// no optimizations are enabled + NoOptimizations, + /// default optimizations are enabled + Normal, +} + +impl Default for OptimizationMode { + fn default() -> Self { + OptimizationMode::Normal + } +} + +/// compiler independent config options +#[derive(Clone, Debug, Default)] +pub struct CompilerIndependentConfig { + /// optimization mode + pub optimization_mode: OptimizationMode, +} + +/// main compiler backend trait +pub trait Compiler: Copy + Send + Sync + 'static { + /// the compiler's configuration + type Config: Default + Clone + From + Send + Sync; + /// get shader compiler's name + fn name(self) -> &'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( + self, + user: U, + config: Self::Config, + ) -> Result>, U::Error>; +} + +#[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: ::types::VecNx4, + } + } +} diff --git a/shader-compiler-backend/src/types.rs b/shader-compiler-backend/src/types.rs new file mode 100644 index 0000000..19167c8 --- /dev/null +++ b/shader-compiler-backend/src/types.rs @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright 2018 Jacob Lifshay + +//! types in backend IR + +use super::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::types::BuildableType for $name { + fn build<'a, Ty: $crate::types::Type<'a>, TB: $crate::types::TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty { + type_builder.build_struct(&[$(<$member_type as $crate::types::BuildableType>::build(type_builder),)*]) + } + } + + impl $crate::types::BuildableStruct for $name { + fn get_members( + ) -> &'static [$crate::types::BuildableStructMemberDescriptor] { + #[allow(dead_code, non_camel_case_types)] + #[repr(usize)] + enum MemberIndices { + $($member_name,)* + __Last, + } + const MEMBERS: &'static [$crate::types::BuildableStructMemberDescriptor] = &[ + $($crate::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); diff --git a/shader-compiler-llvm-7/Cargo.toml b/shader-compiler-llvm-7/Cargo.toml deleted file mode 100644 index b353559..0000000 --- a/shader-compiler-llvm-7/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -# Copyright 2018 Jacob Lifshay -[package] -name = "shader-compiler-llvm-7" -version = "0.1.0" -authors = ["Jacob Lifshay "] -license = "LGPL-2.1-or-later" - -[lib] -crate-type = ["rlib"] - -[dependencies] -shader-compiler = {path = "../shader-compiler"} - -[build-dependencies] -cmake = "0.1.35" -bindgen = "0.42" -tar = "0.4.17" -reqwest = "0.9" -xz2 = "0.1.6" -ring = "0.13" -cc = "1.0" -fs2 = "0.4.3" -which = "2.0.0" diff --git a/shader-compiler-llvm-7/build.rs b/shader-compiler-llvm-7/build.rs deleted file mode 100644 index c45929b..0000000 --- a/shader-compiler-llvm-7/build.rs +++ /dev/null @@ -1,310 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay - -// Partially based on llvm-sys; llvm-sys's license is reproduced below: - -// Copyright (c) 2015 Peter Marheine -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -// of the Software, and to permit persons to whom the Software is furnished to do -// so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -extern crate bindgen; -extern crate cc; -extern crate cmake; -extern crate fs2; -extern crate reqwest; -extern crate ring; -extern crate tar; -extern crate which; -extern crate xz2; -use fs2::FileExt; -use std::env; -use std::ffi::OsStr; -use std::fs; -use std::io; -use std::io::prelude::*; -use std::path::{Path, PathBuf}; -use std::process::Command; - -const LLVM_7_SOURCE_TAR_XZ_URL: &'static str = - "http://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz"; - -const LLVM_7_SOURCE_TAR_XZ_SHA256_HASH: &'static [u8; 32] = &[ - 0x8b, 0xc1, 0xf8, 0x44, 0xe6, 0xcb, 0xde, 0x1b, 0x65, 0x2c, 0x19, 0xc1, 0xed, 0xeb, 0xc1, 0x86, - 0x44, 0x56, 0xfd, 0x9c, 0x78, 0xb8, 0xc1, 0xbe, 0xa0, 0x38, 0xe5, 0x1b, 0x36, 0x3f, 0xe2, 0x22, -]; - -const LLVM_7_SOURCE_DIR_SUFFIX: &'static str = "llvm-7.0.0.src"; - -fn verify_sha256(mut f: fs::File, file_path: &Path) -> fs::File { - f.seek(io::SeekFrom::Start(0)).unwrap(); - let mut context = ring::digest::Context::new(&ring::digest::SHA256); - let mut buffer = [0; 1 << 12]; // 4KiB - loop { - let count = f.read(&mut buffer).unwrap(); - if count == 0 { - break; - } - context.update(&buffer[..count]); - } - let hash = context.finish(); - if hash.as_ref() != LLVM_7_SOURCE_TAR_XZ_SHA256_HASH { - panic!( - "file is corrupted: SHA256 doesn't match; try deleting {} and rerunning cargo", - file_path.display(), - ); - } - f.seek(io::SeekFrom::Start(0)).unwrap(); - f -} - -fn download_llvm_7(out_dir: &Path) -> io::Result { - let filename = LLVM_7_SOURCE_TAR_XZ_URL.rsplit('/').next().unwrap(); - let file_path = out_dir.join(filename); - match fs::File::open(&file_path) { - Ok(file) => return Ok(verify_sha256(file, &file_path)), - Err(ref error) if error.kind() == io::ErrorKind::NotFound => {} - Err(error) => return Err(error), - }; - let response = reqwest::get(LLVM_7_SOURCE_TAR_XZ_URL) - .map_err(|v| io::Error::new(io::ErrorKind::Other, v))?; - let file = fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(&file_path)?; - { response } - .copy_to(&mut { file }) - .map_err(|v| io::Error::new(io::ErrorKind::Other, v))?; - Ok(verify_sha256(fs::File::open(&file_path)?, &file_path)) -} - -fn extract_tar_xz>(r: R, target_path: T) -> io::Result<()> { - tar::Archive::new(xz2::read::XzDecoder::new(r)).unpack(target_path) -} - -fn download_and_extract_llvm_7_if_needed(llvm_dir: &Path) -> io::Result { - let source_dir = llvm_dir.join(LLVM_7_SOURCE_DIR_SUFFIX); - match fs::File::open(source_dir.join("CMakeLists.txt")) { - Ok(_) => return Ok(source_dir), - Err(ref error) if error.kind() == io::ErrorKind::NotFound => {} - Err(error) => return Err(error), - } - extract_tar_xz(download_llvm_7(llvm_dir)?, llvm_dir)?; - Ok(source_dir) -} - -fn make_config(llvm_dir: &Path) -> cmake::Config { - let mut retval = cmake::Config::new(llvm_dir.join(LLVM_7_SOURCE_DIR_SUFFIX)); - let found_ccache = match which::which("ccache") { - Err(ref error) if error.kind() == which::ErrorKind::CannotFindBinaryPath => false, - result => { - result.unwrap(); - true - } - }; - retval - .generator("Ninja") - .define("LLVM_TARGETS_TO_BUILD", "host") - .define("LLVM_CCACHE_BUILD", if found_ccache { "ON" } else { "OFF" }) - .define( - "LLVM_TARGET_ARCH", - env::var("TARGET").unwrap().split("-").next().unwrap(), - ) - .out_dir(llvm_dir) - .profile("Debug") - .always_configure(false); - retval -} - -fn llvm_config, S: AsRef>( - llvm_config_path: &Path, - args: A, -) -> String { - String::from_utf8( - Command::new(llvm_config_path) - .arg("--link-static") - .args(args) - .output() - .unwrap() - .stdout, - ) - .unwrap() -} - -fn get_libs, S: AsRef>( - llvm_config_path: &Path, - args: A, -) -> Vec { - llvm_config(llvm_config_path, args) - .split_whitespace() - .chain(llvm_config(llvm_config_path, Some("--system-libs")).split_whitespace()) - .filter_map(|flag| { - if flag == "" { - None - } else if cfg!(target_env = "msvc") { - // Same as --libnames, foo.lib - assert!(flag.ends_with(".lib")); - Some(&flag[..flag.len() - 4]) - } else { - // Linker flags style, -lfoo - assert!(flag.starts_with("-l")); - Some(&flag[2..]) - } - }) - .map(Into::into) - .collect() -} - -struct LockedFile(fs::File); - -impl Drop for LockedFile { - fn drop(&mut self) { - let _ = self.0.unlock(); - } -} - -impl LockedFile { - fn new>(file_path: T) -> io::Result { - let file = fs::OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(file_path)?; - file.lock_exclusive()?; - Ok(LockedFile(file)) - } -} - -fn build_llvm() -> PathBuf { - assert_eq!( - env::var_os("TARGET"), - env::var_os("HOST"), - "cross-compilation is not supported" - ); - let llvm_dir = env::current_dir() - .unwrap() - .join("..") - .join("external") - .join("llvm-7") - .join(env::var_os("TARGET").unwrap()); - fs::create_dir_all(&llvm_dir).unwrap(); - let _locked_file = LockedFile::new(llvm_dir.join(".build-lock")).unwrap(); - download_and_extract_llvm_7_if_needed(&llvm_dir).unwrap(); - make_config(&llvm_dir).build_target("install").build(); - #[cfg(windows)] - let llvm_config_path = llvm_dir.join("bin").join("llvm-config.exe"); - #[cfg(not(windows))] - let llvm_config_path = llvm_dir.join("bin").join("llvm-config"); - llvm_config_path -} - -fn main() { - let out_dir = Path::new(&env::var_os("OUT_DIR").unwrap()).to_path_buf(); - let llvm_config_path = build_llvm(); - println!( - "cargo:rustc-link-search=native={}", - llvm_config(&llvm_config_path, Some("--libdir")) - ); - let llvm_libs = get_libs( - &llvm_config_path, - &["--libs", "orcjit", "native", "analysis"], - ); - let header = r#" -#include "llvm-c/Core.h" -#include "llvm-c/OrcBindings.h" -#include "llvm-c/Target.h" -#include "llvm-c/Analysis.h" -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -void LLVM_InitializeNativeTarget(void); -void LLVM_InitializeNativeAsmParser(void); -void LLVM_InitializeNativeAsmPrinter(void); -void LLVM_InitializeNativeDisassembler(void); - -#ifdef __cplusplus -} -#endif -"#; - let header_path = out_dir.join("llvm_bindings.h"); - fs::write(&header_path, header).unwrap(); - let llvm_bindings_source = format!("#include {:?}\n", header_path) + r#" -void LLVM_InitializeNativeTarget(void) -{ - LLVM_NATIVE_TARGETINFO(); - LLVM_NATIVE_TARGET(); - LLVM_NATIVE_TARGETMC(); -} - -void LLVM_InitializeNativeAsmParser(void) -{ - LLVM_NATIVE_ASMPARSER(); -} - -void LLVM_InitializeNativeAsmPrinter(void) -{ - LLVM_NATIVE_ASMPRINTER(); -} - -void LLVM_InitializeNativeDisassembler(void) -{ - LLVM_NATIVE_DISASSEMBLER(); -} -"#; - let llvm_bindings_path = out_dir.join("llvm_bindings.c"); - fs::write(&llvm_bindings_path, llvm_bindings_source).unwrap(); - let include_dir: String = llvm_config(&llvm_config_path, Some("--includedir")) - .trim_right() - .into(); - let builder = bindgen::Builder::default() - .header(header_path.to_str().unwrap()) - .clang_arg("-I") - .clang_arg(&include_dir as &str) - .rustfmt_bindings(true) - .whitelist_type("LLVM.*") - .whitelist_function("LLVM.*") - .whitelist_var("LLVM.*") - .blacklist_type("^__.*") - .prepend_enum_name(false) - .constified_enum("LLVM.*"); - builder - .generate() - .unwrap() - .write_to_file(out_dir.join("llvm_c.rs")) - .unwrap(); - let build_llvm_bindings = || { - let mut retval = cc::Build::new(); - retval - .cpp(true) - .file(&llvm_bindings_path) - .include(&include_dir); - retval - }; - build_llvm_bindings() - .cpp_link_stdlib(None) - .compile("llvm_bindings"); - for lib in llvm_libs { - println!("cargo:rustc-link-lib={}", lib); - } - // build twice to get the c++ standard library linked after LLVM with llvm_bindings before LLVM - build_llvm_bindings().compile("llvm_bindings"); -} diff --git a/shader-compiler-llvm-7/src/backend.rs b/shader-compiler-llvm-7/src/backend.rs deleted file mode 100644 index 26964bf..0000000 --- a/shader-compiler-llvm-7/src/backend.rs +++ /dev/null @@ -1,655 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay -use llvm; -use shader_compiler::backend; -use std::cell::RefCell; -use std::collections::HashMap; -use std::collections::HashSet; -use std::ffi::{CStr, CString}; -use std::fmt; -use std::hash::Hash; -use std::mem; -use std::mem::ManuallyDrop; -use std::ops::Deref; -use std::os::raw::{c_char, c_uint}; -use std::ptr::null_mut; -use std::ptr::NonNull; -use std::sync::{Once, ONCE_INIT}; - -fn to_bool(v: llvm::LLVMBool) -> bool { - v != 0 -} - -#[derive(Clone)] -pub struct LLVM7CompilerConfig { - pub variable_vector_length_multiplier: u32, - pub optimization_mode: backend::OptimizationMode, -} - -impl Default for LLVM7CompilerConfig { - fn default() -> Self { - backend::CompilerIndependentConfig::default().into() - } -} - -impl From for LLVM7CompilerConfig { - fn from(v: backend::CompilerIndependentConfig) -> Self { - let backend::CompilerIndependentConfig { optimization_mode } = v; - Self { - variable_vector_length_multiplier: 1, - optimization_mode, - } - } -} - -#[repr(transparent)] -struct LLVM7String(NonNull); - -impl Drop for LLVM7String { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeMessage(self.0.as_ptr()); - } - } -} - -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::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(|v| Self::from_nonnull(v)) - } -} - -impl fmt::Debug for LLVM7String { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - -#[derive(Clone, Eq, PartialEq, Hash)] -#[repr(transparent)] -pub struct LLVM7Type(llvm::LLVMTypeRef); - -impl fmt::Debug for LLVM7Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - let string = - LLVM7String::from_ptr(llvm::LLVMPrintTypeToString(self.0)).ok_or(fmt::Error)?; - f.write_str(&string.to_string_lossy()) - } - } -} - -impl<'a> backend::types::Type<'a> for LLVM7Type { - type Context = LLVM7Context; -} - -pub struct LLVM7TypeBuilder { - context: llvm::LLVMContextRef, - variable_vector_length_multiplier: u32, -} - -impl<'a> backend::types::TypeBuilder<'a, LLVM7Type> for LLVM7TypeBuilder { - fn build_bool(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMInt1TypeInContext(self.context)) } - } - fn build_i8(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMInt8TypeInContext(self.context)) } - } - fn build_i16(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMInt16TypeInContext(self.context)) } - } - fn build_i32(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMInt32TypeInContext(self.context)) } - } - fn build_i64(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMInt64TypeInContext(self.context)) } - } - fn build_f32(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMFloatTypeInContext(self.context)) } - } - fn build_f64(&self) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMDoubleTypeInContext(self.context)) } - } - fn build_pointer(&self, target: LLVM7Type) -> LLVM7Type { - unsafe { LLVM7Type(llvm::LLVMPointerType(target.0, 0)) } - } - fn build_array(&self, element: LLVM7Type, count: usize) -> LLVM7Type { - assert_eq!(count as u32 as usize, count); - unsafe { LLVM7Type(llvm::LLVMArrayType(element.0, count as u32)) } - } - fn build_vector(&self, element: LLVM7Type, length: backend::types::VectorLength) -> LLVM7Type { - use self::backend::types::VectorLength::*; - let length = match length { - Fixed { length } => length, - Variable { base_length } => base_length - .checked_mul(self.variable_vector_length_multiplier) - .unwrap(), - }; - assert_ne!(length, 0); - unsafe { LLVM7Type(llvm::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::LLVMStructTypeInContext( - self.context, - members.as_ptr() as *mut llvm::LLVMTypeRef, - members.len() as c_uint, - false as llvm::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::LLVMFunctionType( - return_type - .unwrap_or_else(|| LLVM7Type(llvm::LLVMVoidTypeInContext(self.context))) - .0, - arguments.as_ptr() as *mut llvm::LLVMTypeRef, - arguments.len() as c_uint, - false as llvm::LLVMBool, - )) - } - } -} - -#[derive(Clone)] -#[repr(transparent)] -pub struct LLVM7Value(llvm::LLVMValueRef); - -impl fmt::Debug for LLVM7Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - let string = - LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.0)).ok_or(fmt::Error)?; - f.write_str(&string.to_string_lossy()) - } - } -} - -impl<'a> backend::Value<'a> for LLVM7Value { - type Context = LLVM7Context; -} - -#[derive(Clone)] -#[repr(transparent)] -pub struct LLVM7BasicBlock(llvm::LLVMBasicBlockRef); - -impl fmt::Debug for LLVM7BasicBlock { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::backend::BasicBlock; - unsafe { - let string = LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.as_value().0)) - .ok_or(fmt::Error)?; - f.write_str(&string.to_string_lossy()) - } - } -} - -impl<'a> backend::BasicBlock<'a> for LLVM7BasicBlock { - type Context = LLVM7Context; - fn as_value(&self) -> LLVM7Value { - unsafe { LLVM7Value(llvm::LLVMBasicBlockAsValue(self.0)) } - } -} - -impl<'a> backend::BuildableBasicBlock<'a> for LLVM7BasicBlock { - type Context = LLVM7Context; - fn as_basic_block(&self) -> LLVM7BasicBlock { - self.clone() - } -} - -pub struct LLVM7Function { - context: llvm::LLVMContextRef, - function: llvm::LLVMValueRef, - parameters: Box<[LLVM7Value]>, -} - -impl fmt::Debug for LLVM7Function { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - let string = LLVM7String::from_ptr(llvm::LLVMPrintValueToString(self.function)) - .ok_or(fmt::Error)?; - f.write_str(&string.to_string_lossy()) - } - } -} - -impl<'a> backend::Function<'a> for LLVM7Function { - type Context = LLVM7Context; - fn as_value(&self) -> LLVM7Value { - LLVM7Value(self.function) - } - fn append_new_basic_block(&mut self, name: Option<&str>) -> LLVM7BasicBlock { - let name = CString::new(name.unwrap_or("")).unwrap(); - unsafe { - LLVM7BasicBlock(llvm::LLVMAppendBasicBlockInContext( - self.context, - self.function, - name.as_ptr(), - )) - } - } - fn parameters(&self) -> &[LLVM7Value] { - &self.parameters - } -} - -pub struct LLVM7Context { - context: Option>, - modules: ManuallyDrop>>, - config: LLVM7CompilerConfig, -} - -impl Drop for LLVM7Context { - fn drop(&mut self) { - unsafe { - ManuallyDrop::drop(&mut self.modules); - if let Some(context) = &mut self.context { - ManuallyDrop::drop(context); - } - } - } -} - -impl<'a> backend::Context<'a> for LLVM7Context { - type Value = LLVM7Value; - type BasicBlock = LLVM7BasicBlock; - type BuildableBasicBlock = LLVM7BasicBlock; - type Function = LLVM7Function; - type Type = LLVM7Type; - type TypeBuilder = LLVM7TypeBuilder; - type Module = LLVM7Module; - type VerifiedModule = LLVM7Module; - type AttachedBuilder = LLVM7Builder; - type DetachedBuilder = LLVM7Builder; - fn create_module(&self, name: &str) -> LLVM7Module { - let name = CString::new(name).unwrap(); - let mut modules = self.modules.borrow_mut(); - unsafe { - let module = OwnedModule(llvm::LLVMModuleCreateWithNameInContext( - name.as_ptr(), - self.context.as_ref().unwrap().0, - )); - let module_ref = module.0; - modules.push(module); - LLVM7Module { - context: self.context.as_ref().unwrap().0, - module: module_ref, - name_set: HashSet::new(), - } - } - } - fn create_builder(&self) -> LLVM7Builder { - unsafe { - LLVM7Builder(llvm::LLVMCreateBuilderInContext( - self.context.as_ref().unwrap().0, - )) - } - } - fn create_type_builder(&self) -> LLVM7TypeBuilder { - LLVM7TypeBuilder { - context: self.context.as_ref().unwrap().0, - variable_vector_length_multiplier: self.config.variable_vector_length_multiplier, - } - } -} - -#[repr(transparent)] -pub struct LLVM7Builder(llvm::LLVMBuilderRef); - -impl Drop for LLVM7Builder { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeBuilder(self.0); - } - } -} - -impl<'a> backend::AttachedBuilder<'a> for LLVM7Builder { - type Context = LLVM7Context; - fn current_basic_block(&self) -> LLVM7BasicBlock { - unsafe { LLVM7BasicBlock(llvm::LLVMGetInsertBlock(self.0)) } - } - fn build_return(self, value: Option) -> LLVM7Builder { - unsafe { - match value { - Some(value) => llvm::LLVMBuildRet(self.0, value.0), - None => llvm::LLVMBuildRetVoid(self.0), - }; - llvm::LLVMClearInsertionPosition(self.0); - } - self - } -} - -impl<'a> backend::DetachedBuilder<'a> for LLVM7Builder { - type Context = LLVM7Context; - fn attach(self, basic_block: LLVM7BasicBlock) -> LLVM7Builder { - unsafe { - llvm::LLVMPositionBuilderAtEnd(self.0, basic_block.0); - } - self - } -} - -struct OwnedModule(llvm::LLVMModuleRef); - -impl Drop for OwnedModule { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeModule(self.0); - } - } -} - -impl OwnedModule { - unsafe fn take(mut self) -> llvm::LLVMModuleRef { - let retval = self.0; - self.0 = null_mut(); - retval - } -} - -struct OwnedContext(llvm::LLVMContextRef); - -impl Drop for OwnedContext { - fn drop(&mut self) { - unsafe { - llvm::LLVMContextDispose(self.0); - } - } -} - -pub struct LLVM7Module { - context: llvm::LLVMContextRef, - module: llvm::LLVMModuleRef, - name_set: HashSet, -} - -impl fmt::Debug for LLVM7Module { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - let string = LLVM7String::from_ptr(llvm::LLVMPrintModuleToString(self.module)) - .ok_or(fmt::Error)?; - f.write_str(&string.to_string_lossy()) - } - } -} - -impl<'a> backend::Module<'a> for LLVM7Module { - type Context = LLVM7Context; - fn set_source_file_name(&mut self, source_file_name: &str) { - unsafe { - llvm::LLVMSetSourceFileName( - self.module, - source_file_name.as_ptr() as *const c_char, - source_file_name.len(), - ) - } - } - fn add_function(&mut self, name: &str, ty: LLVM7Type) -> LLVM7Function { - fn is_start_char(c: char) -> bool { - if c.is_ascii_alphabetic() { - true - } else { - match c { - '_' | '.' | '$' | '-' => true, - _ => false, - } - } - } - fn is_continue_char(c: char) -> bool { - is_start_char(c) || c.is_ascii_digit() - } - assert!(is_start_char(name.chars().next().unwrap())); - assert!(name.chars().all(is_continue_char)); - assert!(self.name_set.insert(name.into())); - let name = CString::new(name).unwrap(); - unsafe { - let function = llvm::LLVMAddFunction(self.module, name.as_ptr(), ty.0); - let mut parameters = Vec::new(); - parameters.resize(llvm::LLVMCountParams(function) as usize, null_mut()); - llvm::LLVMGetParams(function, parameters.as_mut_ptr()); - let parameters: Vec<_> = parameters.into_iter().map(LLVM7Value).collect(); - LLVM7Function { - context: self.context, - function: llvm::LLVMAddFunction(self.module, name.as_ptr(), ty.0), - parameters: parameters.into_boxed_slice(), - } - } - } - fn verify(self) -> Result> { - unsafe { - let mut message = null_mut(); - let broken = to_bool(llvm::LLVMVerifyModule( - self.module, - llvm::LLVMReturnStatusAction, - &mut message, - )); - if broken { - let message = LLVM7String::from_ptr(message).unwrap(); - let message = message.to_string_lossy(); - Err(backend::VerificationFailure::new(self, message.as_ref())) - } else { - Ok(self) - } - } - } - unsafe fn to_verified_module_unchecked(self) -> LLVM7Module { - self - } -} - -impl<'a> backend::VerifiedModule<'a> for LLVM7Module { - type Context = LLVM7Context; - fn into_module(self) -> LLVM7Module { - self - } -} - -struct LLVM7TargetMachine(llvm::LLVMTargetMachineRef); - -impl Drop for LLVM7TargetMachine { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeTargetMachine(self.0); - } - } -} - -impl LLVM7TargetMachine { - fn take(mut self) -> llvm::LLVMTargetMachineRef { - let retval = self.0; - self.0 = null_mut(); - retval - } -} - -struct LLVM7OrcJITStack(llvm::LLVMOrcJITStackRef); - -impl Drop for LLVM7OrcJITStack { - fn drop(&mut self) { - unsafe { - match llvm::LLVMOrcDisposeInstance(self.0) { - llvm::LLVMOrcErrSuccess => {} - _ => { - panic!("LLVMOrcDisposeInstance failed"); - } - } - } - } -} - -fn initialize_native_target() { - static ONCE: Once = ONCE_INIT; - ONCE.call_once(|| unsafe { - llvm::LLVM_InitializeNativeTarget(); - llvm::LLVM_InitializeNativeAsmPrinter(); - llvm::LLVM_InitializeNativeAsmParser(); - }); -} - -extern "C" fn symbol_resolver_fn(name: *const c_char, _lookup_context: *mut Void) -> u64 { - let name = unsafe { CStr::from_ptr(name) }; - panic!("symbol_resolver_fn is unimplemented: name = {:?}", name) -} - -#[derive(Copy, Clone)] -pub struct LLVM7Compiler; - -impl backend::Compiler for LLVM7Compiler { - type Config = LLVM7CompilerConfig; - fn name(self) -> &'static str { - "LLVM 7" - } - fn run( - self, - user: U, - config: LLVM7CompilerConfig, - ) -> Result>, U::Error> { - unsafe { - initialize_native_target(); - let context = OwnedContext(llvm::LLVMContextCreate()); - let modules = Vec::new(); - let mut context = LLVM7Context { - context: Some(ManuallyDrop::new(context)), - modules: ManuallyDrop::new(RefCell::new(modules)), - config: config.clone(), - }; - let backend::CompileInputs { - module, - callable_functions, - } = user.run(&context)?; - let callable_functions: Vec<_> = callable_functions - .into_iter() - .map(|(key, callable_function)| { - assert_eq!( - llvm::LLVMGetGlobalParent(callable_function.function), - module.module - ); - let name: CString = - CStr::from_ptr(llvm::LLVMGetValueName(callable_function.function)).into(); - assert_ne!(name.to_bytes().len(), 0); - (key, name) - }) - .collect(); - let module = context - .modules - .get_mut() - .drain(..) - .find(|v| v.0 == module.module) - .unwrap(); - let target_triple = LLVM7String::from_ptr(llvm::LLVMGetDefaultTargetTriple()).unwrap(); - let mut target = null_mut(); - let mut error = null_mut(); - let success = !to_bool(llvm::LLVMGetTargetFromTriple( - target_triple.as_ptr(), - &mut target, - &mut error, - )); - if !success { - let error = LLVM7String::from_ptr(error).unwrap(); - return Err(U::create_error(error.to_string_lossy().into())); - } - if !to_bool(llvm::LLVMTargetHasJIT(target)) { - return Err(U::create_error(format!( - "target {:?} doesn't support JIT", - target_triple - ))); - } - let host_cpu_name = LLVM7String::from_ptr(llvm::LLVMGetHostCPUName()).unwrap(); - let host_cpu_features = LLVM7String::from_ptr(llvm::LLVMGetHostCPUFeatures()).unwrap(); - let target_machine = LLVM7TargetMachine(llvm::LLVMCreateTargetMachine( - target, - target_triple.as_ptr(), - host_cpu_name.as_ptr(), - host_cpu_features.as_ptr(), - match config.optimization_mode { - backend::OptimizationMode::NoOptimizations => llvm::LLVMCodeGenLevelNone, - backend::OptimizationMode::Normal => llvm::LLVMCodeGenLevelDefault, - }, - llvm::LLVMRelocDefault, - llvm::LLVMCodeModelJITDefault, - )); - assert!(!target_machine.0.is_null()); - let orc_jit_stack = - LLVM7OrcJITStack(llvm::LLVMOrcCreateInstance(target_machine.take())); - let mut module_handle = 0; - if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcAddEagerlyCompiledIR( - orc_jit_stack.0, - &mut module_handle, - module.take(), - Some(symbol_resolver_fn), - null_mut(), - ) { - return Err(U::create_error("compilation failed".into())); - } - let mut functions: HashMap<_, _> = HashMap::new(); - for (key, name) in callable_functions { - let mut address: llvm::LLVMOrcTargetAddress = mem::zeroed(); - if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcGetSymbolAddressIn( - orc_jit_stack.0, - &mut address, - module_handle, - name.as_ptr(), - ) { - return Err(U::create_error(format!( - "function not found in compiled module: {:?}", - name - ))); - } - let address: Option = mem::transmute(address as usize); - if functions.insert(key, address.unwrap()).is_some() { - return Err(U::create_error(format!("duplicate function: {:?}", name))); - } - } - struct CompiledCode { - functions: HashMap, - orc_jit_stack: ManuallyDrop, - context: ManuallyDrop, - } - unsafe impl Send for CompiledCode {} - unsafe impl Sync for CompiledCode {} - impl Drop for CompiledCode { - fn drop(&mut self) { - unsafe { - ManuallyDrop::drop(&mut self.orc_jit_stack); - ManuallyDrop::drop(&mut self.context); - } - } - } - impl backend::CompiledCode for CompiledCode { - fn get(&self, key: &K) -> Option { - Some(*self.functions.get(key)?) - } - } - Ok(Box::new(CompiledCode { - functions, - orc_jit_stack: ManuallyDrop::new(orc_jit_stack), - context: context.context.take().unwrap(), - })) - } - } -} diff --git a/shader-compiler-llvm-7/src/lib.rs b/shader-compiler-llvm-7/src/lib.rs deleted file mode 100644 index d797122..0000000 --- a/shader-compiler-llvm-7/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay -extern crate shader_compiler; - -#[cfg_attr(feature = "cargo-clippy", allow(clippy::const_static_lifetime))] -#[allow(dead_code)] -#[allow(non_upper_case_globals)] -#[allow(non_camel_case_types)] -mod llvm { - include!(concat!(env!("OUT_DIR"), "/llvm_c.rs")); -} - -mod backend; -mod tests; - -pub use backend::LLVM7CompilerConfig; - -pub const LLVM_7_SHADER_COMPILER: backend::LLVM7Compiler = backend::LLVM7Compiler; diff --git a/shader-compiler-llvm-7/src/tests.rs b/shader-compiler-llvm-7/src/tests.rs deleted file mode 100644 index ac532cf..0000000 --- a/shader-compiler-llvm-7/src/tests.rs +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay -#[cfg(test)] -// we have a tests module inside a tests module to have rls parse this tests.rs file -#[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] -mod tests { - use shader_compiler::backend::types::TypeBuilder; - use shader_compiler::backend::*; - use std::mem; - - fn make_compiler() -> impl Compiler { - ::LLVM_7_SHADER_COMPILER - } - - #[test] - fn test_basic() { - type GeneratedFunctionType = unsafe extern "C" fn(u32); - #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] - enum FunctionKey { - Function, - } - struct Test; - impl CompilerUser for Test { - type FunctionKey = FunctionKey; - type Error = String; - fn create_error(message: String) -> String { - message - } - fn run<'a, C: Context<'a>>( - self, - context: &'a C, - ) -> Result, String> { - let type_builder = context.create_type_builder(); - let mut module = context.create_module("test_module"); - let mut function = module.add_function( - "test_function", - type_builder.build::(), - ); - let builder = context.create_builder(); - let builder = builder.attach(function.append_new_basic_block(None)); - builder.build_return(None); - let module = module.verify().unwrap(); - Ok(CompileInputs { - module, - callable_functions: vec![(FunctionKey::Function, function)] - .into_iter() - .collect(), - }) - } - } - let compiled_code = make_compiler().run(Test, Default::default()).unwrap(); - let function = compiled_code.get(&FunctionKey::Function).unwrap(); - unsafe { - let function: GeneratedFunctionType = mem::transmute(function); - function(0); - } - } - - #[test] - fn test_names() { - const NAMES: &[&str] = &["main", "abc123-$._"]; - type GeneratedFunctionType = unsafe extern "C" fn(u32); - #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] - struct Test; - impl CompilerUser for Test { - type FunctionKey = String; - type Error = String; - fn create_error(message: String) -> String { - message - } - fn run<'a, C: Context<'a>>( - self, - context: &'a C, - ) -> Result, String> { - let type_builder = context.create_type_builder(); - let mut module = context.create_module("test_module"); - let mut functions = Vec::new(); - let mut detached_builder = context.create_builder(); - for name in NAMES { - let mut function = - module.add_function(name, type_builder.build::()); - let builder = detached_builder.attach(function.append_new_basic_block(None)); - detached_builder = builder.build_return(None); - functions.push((name.to_string(), function)); - } - let module = module.verify().unwrap(); - Ok(CompileInputs { - module, - callable_functions: functions.into_iter().collect(), - }) - } - } - let compiled_code = make_compiler().run(Test, Default::default()).unwrap(); - let function = compiled_code.get(&"main".to_string()).unwrap(); - unsafe { - let function: GeneratedFunctionType = mem::transmute(function); - function(0); - } - } -} diff --git a/shader-compiler/Cargo.toml b/shader-compiler/Cargo.toml deleted file mode 100644 index 25f1138..0000000 --- a/shader-compiler/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -# Copyright 2018 Jacob Lifshay -[package] -name = "shader-compiler" -version = "0.1.0" -authors = ["Jacob Lifshay "] -license = "LGPL-2.1-or-later" - -[lib] -crate-type = ["rlib"] - -[dependencies] diff --git a/shader-compiler/src/backend/mod.rs b/shader-compiler/src/backend/mod.rs deleted file mode 100644 index 97f7441..0000000 --- a/shader-compiler/src/backend/mod.rs +++ /dev/null @@ -1,251 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay - -//! Shader Compiler Backend traits - -use std::collections::HashMap; -use std::error::Error; -use std::fmt; -use std::fmt::Debug; -use std::hash::Hash; -use std::io; -use std::marker::PhantomData; - -#[macro_use] -pub mod types; - -/// equivalent to LLVM's 'IRBuilder' -pub trait AttachedBuilder<'a>: Sized { - /// the `Context` type - type Context: Context<'a>; - /// get the current `BasicBlock` - fn current_basic_block(&self) -> >::BasicBlock; - /// build a return instruction - fn build_return( - self, - value: Option<>::Value>, - ) -> >::DetachedBuilder; -} - -/// equivalent to LLVM's 'IRBuilder' -pub trait DetachedBuilder<'a>: Sized { - /// the `Context` type - type Context: Context<'a>; - /// attach `basic_block` to `Self`, converting into an `AttachedBuilder` - fn attach( - self, - basic_block: >::BuildableBasicBlock, - ) -> >::AttachedBuilder; -} - -/// equivalent to LLVM's 'Value' -pub trait Value<'a>: Clone + Debug { - /// the `Context` type - type Context: Context<'a>; -} - -/// equivalent to LLVM's 'BasicBlock' -pub trait BasicBlock<'a>: Clone + Debug { - /// the `Context` type - type Context: Context<'a>; - /// get the `Value` corresponding to `Self` - fn as_value(&self) -> >::Value; -} - -/// equivalent to LLVM's 'BasicBlock' -pub trait BuildableBasicBlock<'a>: Debug + Sized { - /// the `Context` type - type Context: Context<'a>; - /// get the `BasicBlock` corresponding to `Self` - fn as_basic_block(&self) -> >::BasicBlock; - /// get the `Value` corresponding to `Self` - fn as_value(&self) -> >::Value { - self.as_basic_block().as_value() - } -} - -/// equivalent to LLVM's 'Function' -pub trait Function<'a>: Debug + Sized { - /// the `Context` type - type Context: Context<'a>; - /// get the `Value` corresponding to `Self` - fn as_value(&self) -> >::Value; - /// append a new `BasicBlock` to `Self` - fn append_new_basic_block( - &mut self, - name: Option<&str>, - ) -> >::BuildableBasicBlock; - /// get this function's parameters - fn parameters(&self) -> &[>::Value]; -} - -/// module verification failure; returned from `Module::verify` -pub struct VerificationFailure<'a, M: Module<'a>> { - module: M, - message: String, - _phantom_data: PhantomData<&'a ()>, -} - -impl<'a, M: Module<'a>> VerificationFailure<'a, M> { - /// create a new `VerificationFailure` - pub fn new(module: M, message: &T) -> Self { - VerificationFailure { - module, - message: message.to_string(), - _phantom_data: PhantomData, - } - } - /// get the `Module` that failed verification - pub fn into_module(self) -> M { - self.module - } -} - -impl<'a, M: Module<'a>> fmt::Display for VerificationFailure<'a, M> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "module verification failure: {}", self.message,) - } -} - -impl<'a, M: Module<'a>> Debug for VerificationFailure<'a, M> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("VerificationFailure") - .field("message", &self.message) - .field("module", &self.module) - .finish() - } -} - -impl<'a, M: Module<'a>> Error for VerificationFailure<'a, M> {} - -impl<'a, M: Module<'a>> From> for io::Error { - fn from(v: VerificationFailure<'a, M>) -> Self { - io::Error::new(io::ErrorKind::Other, format!("{}", v)) - } -} - -/// equivalent to LLVM's 'Module' -pub trait Module<'a>: Debug + Sized { - /// the `Context` type - type Context: Context<'a>; - /// set's the source file name for this module - fn set_source_file_name(&mut self, source_file_name: &str); - /// add a new empty function to `Self` - fn add_function( - &mut self, - name: &str, - ty: >::Type, - ) -> >::Function; - /// verify `Self`, converting into a `VerifiedModule` - fn verify( - self, - ) -> Result<>::VerifiedModule, VerificationFailure<'a, Self>>; - /// convert into a `VerifiedModule` without verifing - unsafe fn to_verified_module_unchecked(self) -> >::VerifiedModule; -} - -/// equivalent to LLVM's 'Module'; create using `Module::verify` or `Module::to_verified_module_unchecked` -pub trait VerifiedModule<'a>: Debug + Sized { - /// the `Context` type - type Context: Context<'a>; - /// convert back to an unverified module - fn into_module(self) -> >::Module; -} - -/// instance of a compiler backend; equivalent to LLVM's `LLVMContext` -pub trait Context<'a>: Sized { - /// the `Value` type - type Value: Value<'a, Context = Self>; - /// the `BasicBlock` type - type BasicBlock: BasicBlock<'a, Context = Self>; - /// the `BuildableBasicBlock` type - type BuildableBasicBlock: BuildableBasicBlock<'a, Context = Self>; - /// the `Function` type - type Function: Function<'a, Context = Self>; - /// the `Module` type - type Module: Module<'a, Context = Self>; - /// the `VerifiedModule` type - type VerifiedModule: VerifiedModule<'a, Context = Self>; - /// the `AttachedBuilder` type - type AttachedBuilder: AttachedBuilder<'a, Context = Self>; - /// the `DetachedBuilder` type - type DetachedBuilder: DetachedBuilder<'a, Context = Self>; - /// the `Type` type - type Type: types::Type<'a, Context = Self>; - /// the `TypeBuilder` type - type TypeBuilder: types::TypeBuilder<'a, Self::Type>; - /// create a new `Module` - fn create_module(&self, name: &str) -> Self::Module; - /// create a new `DetachedBuilder` - fn create_builder(&self) -> Self::DetachedBuilder; - /// create a new `TypeBuilder` - fn create_type_builder(&self) -> Self::TypeBuilder; -} - -/// inputs to the final compilation -pub struct CompileInputs<'a, C: Context<'a>, K: Hash + Eq + Send + Sync + 'static> { - /// the input module - pub module: C::VerifiedModule, - /// the list of functions that can be called from the final `CompiledCode` - pub callable_functions: HashMap, -} - -/// the final compiled code -pub trait CompiledCode: Send + Sync { - /// get a function in the final compiled code. - /// the returned function needs to be cast to the correct type and - /// `Self` needs to still exist while the returned function exists - fn get(&self, which: &K) -> Option; -} - -/// trait that the user of `Compiler` implements -pub trait CompilerUser { - /// the type used as a key for visible functions - type FunctionKey: Hash + Eq + Send + Sync + 'static; - /// the user's error type - type Error; - /// create an instance of `Error` - fn create_error(message: String) -> Self::Error; - /// the function that the user of `Compiler` implements - fn run<'a, C: Context<'a>>( - self, - context: &'a C, - ) -> Result, Self::Error>; -} - -/// optimization mode -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum OptimizationMode { - /// no optimizations are enabled - NoOptimizations, - /// default optimizations are enabled - Normal, -} - -impl Default for OptimizationMode { - fn default() -> Self { - OptimizationMode::Normal - } -} - -/// compiler independent config options -#[derive(Clone, Debug, Default)] -pub struct CompilerIndependentConfig { - /// optimization mode - pub optimization_mode: OptimizationMode, -} - -/// main compiler backend trait -pub trait Compiler: Copy + Send + Sync + 'static { - /// the compiler's configuration - type Config: Default + Clone + From + Send + Sync; - /// get shader compiler's name - fn name(self) -> &'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( - self, - user: U, - config: Self::Config, - ) -> Result>, U::Error>; -} diff --git a/shader-compiler/src/backend/types.rs b/shader-compiler/src/backend/types.rs deleted file mode 100644 index c364796..0000000 --- a/shader-compiler/src/backend/types.rs +++ /dev/null @@ -1,553 +0,0 @@ -// 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); diff --git a/shader-compiler/src/lib.rs b/shader-compiler/src/lib.rs deleted file mode 100644 index bcbb3f0..0000000 --- a/shader-compiler/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright 2018 Jacob Lifshay -#![deny(missing_docs)] - -//! Shader Compiler for Kazan - -#[macro_use] -pub mod backend; - -#[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::types::VecNx4, - } - } -} diff --git a/vulkan-driver/Cargo.toml b/vulkan-driver/Cargo.toml index b901326..ac2666d 100644 --- a/vulkan-driver/Cargo.toml +++ b/vulkan-driver/Cargo.toml @@ -14,8 +14,8 @@ crate-type = ["cdylib"] enum-map = "0.4" uuid = {version = "0.7", features = ["v5"]} sys-info = "0.5" -shader-compiler = {path = "../shader-compiler"} -shader-compiler-llvm-7 = {path = "../shader-compiler-llvm-7"} +shader-compiler-backend = {path = "../shader-compiler-backend"} +shader-compiler-backend-llvm-7 = {path = "../shader-compiler-backend-llvm-7"} [target.'cfg(unix)'.dependencies] xcb = {version = "0.8", features = ["shm"]} diff --git a/vulkan-driver/src/lib.rs b/vulkan-driver/src/lib.rs index 66fa5a7..8f297d9 100644 --- a/vulkan-driver/src/lib.rs +++ b/vulkan-driver/src/lib.rs @@ -7,7 +7,7 @@ extern crate enum_map; extern crate errno; #[cfg(unix)] extern crate libc; -extern crate shader_compiler; +extern crate shader_compiler_backend; extern crate sys_info; extern crate uuid; #[cfg(unix)]