# Copyright 2018 Jacob Lifshay
[workspace]
members = [
- "shader-compiler",
- "shader-compiler-llvm-7",
+ "shader-compiler-backend",
+ "shader-compiler-backend-llvm-7",
"vulkan-driver",
]
--- /dev/null
+# 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 <programmerjake@gmail.com>"]
+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"
--- /dev/null
+// 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<fs::File> {
+ 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: Read, T: AsRef<Path>>(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<PathBuf> {
+ 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<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
+ 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<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
+ llvm_config_path: &Path,
+ args: A,
+) -> Vec<String> {
+ 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<T: AsRef<Path>>(file_path: T) -> io::Result<Self> {
+ 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 <stdbool.h>
+
+#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");
+}
--- /dev/null
+// 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<backend::CompilerIndependentConfig> 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<c_char>);
+
+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<c_char>) -> Self {
+ LLVM7String(v)
+ }
+ unsafe fn from_ptr(v: *mut c_char) -> Option<Self> {
+ 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>) -> 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<ManuallyDrop<OwnedContext>>,
+ modules: ManuallyDrop<RefCell<Vec<OwnedModule>>>,
+ 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<LLVM7Value>) -> 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<String>,
+}
+
+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<LLVM7Module, backend::VerificationFailure<'a, LLVM7Module>> {
+ 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<Void>(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<U: backend::CompilerUser>(
+ self,
+ user: U,
+ config: LLVM7CompilerConfig,
+ ) -> Result<Box<dyn backend::CompiledCode<U::FunctionKey>>, 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<unsafe extern "C" fn()> = mem::transmute(address as usize);
+ if functions.insert(key, address.unwrap()).is_some() {
+ return Err(U::create_error(format!("duplicate function: {:?}", name)));
+ }
+ }
+ struct CompiledCode<K: Hash + Eq + Send + Sync + 'static> {
+ functions: HashMap<K, unsafe extern "C" fn()>,
+ orc_jit_stack: ManuallyDrop<LLVM7OrcJITStack>,
+ context: ManuallyDrop<OwnedContext>,
+ }
+ unsafe impl<K: Hash + Eq + Send + Sync + 'static> Send for CompiledCode<K> {}
+ unsafe impl<K: Hash + Eq + Send + Sync + 'static> Sync for CompiledCode<K> {}
+ impl<K: Hash + Eq + Send + Sync + 'static> Drop for CompiledCode<K> {
+ fn drop(&mut self) {
+ unsafe {
+ ManuallyDrop::drop(&mut self.orc_jit_stack);
+ ManuallyDrop::drop(&mut self.context);
+ }
+ }
+ }
+ impl<K: Hash + Eq + Send + Sync + 'static> backend::CompiledCode<K> for CompiledCode<K> {
+ fn get(&self, key: &K) -> Option<unsafe extern "C" fn()> {
+ Some(*self.functions.get(key)?)
+ }
+ }
+ Ok(Box::new(CompiledCode {
+ functions,
+ orc_jit_stack: ManuallyDrop::new(orc_jit_stack),
+ context: context.context.take().unwrap(),
+ }))
+ }
+ }
+}
--- /dev/null
+// 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;
--- /dev/null
+// 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<CompileInputs<'a, C, FunctionKey>, 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::<GeneratedFunctionType>(),
+ );
+ 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<CompileInputs<'a, C, String>, 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::<GeneratedFunctionType>());
+ 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);
+ }
+ }
+}
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# Copyright 2018 Jacob Lifshay
+[package]
+name = "shader-compiler-backend"
+version = "0.1.0"
+authors = ["Jacob Lifshay <programmerjake@gmail.com>"]
+license = "LGPL-2.1-or-later"
+
+[lib]
+crate-type = ["rlib"]
+
+[dependencies]
--- /dev/null
+// 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) -> <Self::Context as Context<'a>>::BasicBlock;
+ /// build a return instruction
+ fn build_return(
+ self,
+ value: Option<<Self::Context as Context<'a>>::Value>,
+ ) -> <Self::Context as Context<'a>>::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: <Self::Context as Context<'a>>::BuildableBasicBlock,
+ ) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::BasicBlock;
+ /// get the `Value` corresponding to `Self`
+ fn as_value(&self) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::Value;
+ /// append a new `BasicBlock` to `Self`
+ fn append_new_basic_block(
+ &mut self,
+ name: Option<&str>,
+ ) -> <Self::Context as Context<'a>>::BuildableBasicBlock;
+ /// get this function's parameters
+ fn parameters(&self) -> &[<Self::Context as Context<'a>>::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<T: ToString + ?Sized>(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<VerificationFailure<'a, M>> 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: <Self::Context as Context<'a>>::Type,
+ ) -> <Self::Context as Context<'a>>::Function;
+ /// verify `Self`, converting into a `VerifiedModule`
+ fn verify(
+ self,
+ ) -> Result<<Self::Context as Context<'a>>::VerifiedModule, VerificationFailure<'a, Self>>;
+ /// convert into a `VerifiedModule` without verifing
+ unsafe fn to_verified_module_unchecked(self) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::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<K, C::Function>,
+}
+
+/// the final compiled code
+pub trait CompiledCode<K: Hash + Eq + Send + Sync + 'static>: 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<unsafe extern "C" fn()>;
+}
+
+/// 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<CompileInputs<'a, C, Self::FunctionKey>, 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<CompilerIndependentConfig> + 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<U: CompilerUser>(
+ self,
+ user: U,
+ config: Self::Config,
+ ) -> Result<Box<dyn CompiledCode<U::FunctionKey>>, 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<f32>,
+ }
+ }
+}
--- /dev/null
+// 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>) -> Ty;
+ /// build a type
+ fn build<T: BuildableType>(&self) -> Ty
+ where
+ Self: Sized,
+ {
+ T::build(self)
+ }
+}
+
+impl<'a, 'b, Ty: Type<'a>> TypeBuilder<'a, Ty> for &'b TypeBuilder<'a, Ty> {
+ fn build_bool(&self) -> Ty {
+ (*self).build_bool()
+ }
+ fn build_i8(&self) -> Ty {
+ (*self).build_i8()
+ }
+ fn build_i16(&self) -> Ty {
+ (*self).build_i16()
+ }
+ fn build_i32(&self) -> Ty {
+ (*self).build_i32()
+ }
+ fn build_i64(&self) -> Ty {
+ (*self).build_i64()
+ }
+ fn build_f32(&self) -> Ty {
+ (*self).build_f32()
+ }
+ fn build_f64(&self) -> Ty {
+ (*self).build_f64()
+ }
+ fn build_pointer(&self, target: Ty) -> Ty {
+ (*self).build_pointer(target)
+ }
+ fn build_array(&self, element: Ty, count: usize) -> Ty {
+ (*self).build_array(element, count)
+ }
+ fn build_vector(&self, element: Ty, length: VectorLength) -> Ty {
+ (*self).build_vector(element, length)
+ }
+ fn build_struct(&self, members: &[Ty]) -> Ty {
+ (*self).build_struct(members)
+ }
+ fn build_function(&self, arguments: &[Ty], return_type: Option<Ty>) -> Ty {
+ (*self).build_function(arguments, return_type)
+ }
+}
+
+/// trait for rust types that can be built using `TypeBuilder`
+pub trait BuildableType {
+ /// build the type represented by `Self`
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty;
+}
+
+impl<T: BuildableType> BuildableType for UnsafeCell<T> {
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+ T::build(type_builder)
+ }
+}
+
+mod hidden {
+ pub trait ScalarBuildableTypeBase {}
+}
+
+impl<T: hidden::ScalarBuildableTypeBase> hidden::ScalarBuildableTypeBase for UnsafeCell<T> {}
+
+/// trait for rust types that can be an element of a vector and be built using `TypeBuilder`
+pub trait ScalarBuildableType: BuildableType + hidden::ScalarBuildableTypeBase {}
+
+impl<T: ScalarBuildableType> ScalarBuildableType for UnsafeCell<T> {}
+
+/// descriptor for members of types implementing `BuildableStruct`
+pub struct BuildableStructMemberDescriptor {
+ /// name of member
+ pub name: &'static str,
+ /// index of member
+ pub index: usize,
+}
+
+/// trait for structs that can be built using TypeBuilder
+/// implementing types are usually created using `buildable_struct!`
+pub trait BuildableStruct: BuildableType {
+ /// get the list of members for `Self`
+ fn get_members() -> &'static [BuildableStructMemberDescriptor];
+ /// get the member for `Self` that is named `name`
+ fn get_member_by_name(name: &str) -> &'static BuildableStructMemberDescriptor {
+ for member in Self::get_members() {
+ if name == member.name {
+ return member;
+ }
+ }
+ unreachable!("{} is not a member", name);
+ }
+}
+
+macro_rules! build_basic_scalar {
+ ($type:ty, $build_fn:ident) => {
+ impl BuildableType for $type {
+ fn build<'a, 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<T: BuildableType> 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<T: BuildableType> 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<T: BuildableType> BuildableType for NonNull<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 NonNull<T> {}
+
+impl<'b, T: BuildableType> ScalarBuildableType for NonNull<T> {}
+
+impl<T: BuildableType> BuildableType for Option<NonNull<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<NonNull<T>> {}
+
+impl<'b, T: BuildableType> ScalarBuildableType for Option<NonNull<T>> {}
+
+macro_rules! build_unit_function_type {
+ ($($arguments:ident,)*) => {
+ impl<$($arguments: BuildableType),*> BuildableType for Option<unsafe extern "C" fn($($arguments,)*)> {
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+ type_builder.build_function(&[$($arguments::build(type_builder),)*], None)
+ }
+ }
+
+ impl<$($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option<unsafe extern "C" fn($($arguments,)*)> {}
+
+ impl<$($arguments: BuildableType),*> ScalarBuildableType for Option<unsafe extern "C" fn($($arguments,)*)> {}
+
+ 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<R: BuildableType, $($arguments: BuildableType),*> BuildableType for Option<unsafe extern "C" fn($($arguments,)*) -> R> {
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+ type_builder.build_function(&[$($arguments::build(type_builder),)*], Some(R::build(type_builder)))
+ }
+ }
+
+ impl<R: BuildableType, $($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option<unsafe extern "C" fn($($arguments,)*) -> R> {}
+
+ impl<R: BuildableType, $($arguments: BuildableType),*> ScalarBuildableType for Option<unsafe extern "C" fn($($arguments,)*) -> R> {}
+
+ impl<R: BuildableType, $($arguments: BuildableType),*> 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<R: BuildableType, $($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for unsafe extern "C" fn($($arguments,)*) -> R {}
+
+ impl<R: BuildableType, $($arguments: BuildableType),*> 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<T: BuildableType> 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<Element: ScalarBuildableType> {
+ /// elements of the vector `Self`
+ pub elements: [Element; $length],
+ }
+
+ impl<Element: ScalarBuildableType> Deref for $name<Element> {
+ type Target = [Element; $length];
+ fn deref(&self) -> &Self::Target {
+ &self.elements
+ }
+ }
+
+ impl<Element: ScalarBuildableType> DerefMut for $name<Element> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.elements
+ }
+ }
+
+ impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+ type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
+ }
+ }
+
+ impl<Element: ScalarBuildableType> Vector for $name<Element> {
+ type Element = Element;
+ const LENGTH: VectorLength = { VectorLength::Fixed { length: $length } };
+ }
+ };
+}
+
+macro_rules! build_variable_vector {
+ ($name:ident, $base_length:expr) => {
+ /// Vector of elements `Element`
+ pub enum $name<Element: ScalarBuildableType> {
+ #[doc(hidden)]
+ __Dummy(__VectorNeverType, PhantomData<Element>),
+ }
+
+ impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
+ fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
+ type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
+ }
+ }
+
+ impl<Element: ScalarBuildableType> Vector for $name<Element> {
+ type Element = Element;
+ const LENGTH: VectorLength = {
+ VectorLength::Variable {
+ base_length: $base_length,
+ }
+ };
+ }
+ };
+}
+
+/// alternate name for `VecNx1`
+pub type VecN<Element> = VecNx1<Element>;
+
+build_fixed_vector!(Vec1, 1);
+build_fixed_vector!(Vec2, 2);
+build_fixed_vector!(Vec3, 3);
+build_fixed_vector!(Vec4, 4);
+build_fixed_vector!(Vec5, 5);
+build_fixed_vector!(Vec6, 6);
+build_fixed_vector!(Vec7, 7);
+build_fixed_vector!(Vec8, 8);
+build_fixed_vector!(Vec9, 9);
+build_fixed_vector!(Vec10, 10);
+build_fixed_vector!(Vec11, 11);
+build_fixed_vector!(Vec12, 12);
+build_fixed_vector!(Vec13, 13);
+build_fixed_vector!(Vec14, 14);
+build_fixed_vector!(Vec15, 15);
+build_fixed_vector!(Vec16, 16);
+build_variable_vector!(VecNx1, 1);
+build_variable_vector!(VecNx2, 2);
+build_variable_vector!(VecNx3, 3);
+build_variable_vector!(VecNx4, 4);
+build_variable_vector!(VecNx5, 5);
+build_variable_vector!(VecNx6, 6);
+build_variable_vector!(VecNx7, 7);
+build_variable_vector!(VecNx8, 8);
+build_variable_vector!(VecNx9, 9);
+build_variable_vector!(VecNx10, 10);
+build_variable_vector!(VecNx11, 11);
+build_variable_vector!(VecNx12, 12);
+build_variable_vector!(VecNx13, 13);
+build_variable_vector!(VecNx14, 14);
+build_variable_vector!(VecNx15, 15);
+build_variable_vector!(VecNx16, 16);
+++ /dev/null
-# 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 <programmerjake@gmail.com>"]
-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"
+++ /dev/null
-// 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<fs::File> {
- 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: Read, T: AsRef<Path>>(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<PathBuf> {
- 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<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
- 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<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
- llvm_config_path: &Path,
- args: A,
-) -> Vec<String> {
- 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<T: AsRef<Path>>(file_path: T) -> io::Result<Self> {
- 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 <stdbool.h>
-
-#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");
-}
+++ /dev/null
-// 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<backend::CompilerIndependentConfig> 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<c_char>);
-
-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<c_char>) -> Self {
- LLVM7String(v)
- }
- unsafe fn from_ptr(v: *mut c_char) -> Option<Self> {
- 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>) -> 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<ManuallyDrop<OwnedContext>>,
- modules: ManuallyDrop<RefCell<Vec<OwnedModule>>>,
- 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<LLVM7Value>) -> 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<String>,
-}
-
-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<LLVM7Module, backend::VerificationFailure<'a, LLVM7Module>> {
- 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<Void>(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<U: backend::CompilerUser>(
- self,
- user: U,
- config: LLVM7CompilerConfig,
- ) -> Result<Box<dyn backend::CompiledCode<U::FunctionKey>>, 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<unsafe extern "C" fn()> = mem::transmute(address as usize);
- if functions.insert(key, address.unwrap()).is_some() {
- return Err(U::create_error(format!("duplicate function: {:?}", name)));
- }
- }
- struct CompiledCode<K: Hash + Eq + Send + Sync + 'static> {
- functions: HashMap<K, unsafe extern "C" fn()>,
- orc_jit_stack: ManuallyDrop<LLVM7OrcJITStack>,
- context: ManuallyDrop<OwnedContext>,
- }
- unsafe impl<K: Hash + Eq + Send + Sync + 'static> Send for CompiledCode<K> {}
- unsafe impl<K: Hash + Eq + Send + Sync + 'static> Sync for CompiledCode<K> {}
- impl<K: Hash + Eq + Send + Sync + 'static> Drop for CompiledCode<K> {
- fn drop(&mut self) {
- unsafe {
- ManuallyDrop::drop(&mut self.orc_jit_stack);
- ManuallyDrop::drop(&mut self.context);
- }
- }
- }
- impl<K: Hash + Eq + Send + Sync + 'static> backend::CompiledCode<K> for CompiledCode<K> {
- fn get(&self, key: &K) -> Option<unsafe extern "C" fn()> {
- Some(*self.functions.get(key)?)
- }
- }
- Ok(Box::new(CompiledCode {
- functions,
- orc_jit_stack: ManuallyDrop::new(orc_jit_stack),
- context: context.context.take().unwrap(),
- }))
- }
- }
-}
+++ /dev/null
-// 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;
+++ /dev/null
-// 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<CompileInputs<'a, C, FunctionKey>, 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::<GeneratedFunctionType>(),
- );
- 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<CompileInputs<'a, C, String>, 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::<GeneratedFunctionType>());
- 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);
- }
- }
-}
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# Copyright 2018 Jacob Lifshay
-[package]
-name = "shader-compiler"
-version = "0.1.0"
-authors = ["Jacob Lifshay <programmerjake@gmail.com>"]
-license = "LGPL-2.1-or-later"
-
-[lib]
-crate-type = ["rlib"]
-
-[dependencies]
+++ /dev/null
-// 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) -> <Self::Context as Context<'a>>::BasicBlock;
- /// build a return instruction
- fn build_return(
- self,
- value: Option<<Self::Context as Context<'a>>::Value>,
- ) -> <Self::Context as Context<'a>>::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: <Self::Context as Context<'a>>::BuildableBasicBlock,
- ) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::BasicBlock;
- /// get the `Value` corresponding to `Self`
- fn as_value(&self) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::Value;
- /// append a new `BasicBlock` to `Self`
- fn append_new_basic_block(
- &mut self,
- name: Option<&str>,
- ) -> <Self::Context as Context<'a>>::BuildableBasicBlock;
- /// get this function's parameters
- fn parameters(&self) -> &[<Self::Context as Context<'a>>::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<T: ToString + ?Sized>(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<VerificationFailure<'a, M>> 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: <Self::Context as Context<'a>>::Type,
- ) -> <Self::Context as Context<'a>>::Function;
- /// verify `Self`, converting into a `VerifiedModule`
- fn verify(
- self,
- ) -> Result<<Self::Context as Context<'a>>::VerifiedModule, VerificationFailure<'a, Self>>;
- /// convert into a `VerifiedModule` without verifing
- unsafe fn to_verified_module_unchecked(self) -> <Self::Context as Context<'a>>::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) -> <Self::Context as Context<'a>>::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<K, C::Function>,
-}
-
-/// the final compiled code
-pub trait CompiledCode<K: Hash + Eq + Send + Sync + 'static>: 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<unsafe extern "C" fn()>;
-}
-
-/// 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<CompileInputs<'a, C, Self::FunctionKey>, 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<CompilerIndependentConfig> + 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<U: CompilerUser>(
- self,
- user: U,
- config: Self::Config,
- ) -> Result<Box<dyn CompiledCode<U::FunctionKey>>, U::Error>;
-}
+++ /dev/null
-// 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>) -> Ty;
- /// build a type
- fn build<T: BuildableType>(&self) -> Ty
- where
- Self: Sized,
- {
- T::build(self)
- }
-}
-
-impl<'a, 'b, Ty: Type<'a>> TypeBuilder<'a, Ty> for &'b TypeBuilder<'a, Ty> {
- fn build_bool(&self) -> Ty {
- (*self).build_bool()
- }
- fn build_i8(&self) -> Ty {
- (*self).build_i8()
- }
- fn build_i16(&self) -> Ty {
- (*self).build_i16()
- }
- fn build_i32(&self) -> Ty {
- (*self).build_i32()
- }
- fn build_i64(&self) -> Ty {
- (*self).build_i64()
- }
- fn build_f32(&self) -> Ty {
- (*self).build_f32()
- }
- fn build_f64(&self) -> Ty {
- (*self).build_f64()
- }
- fn build_pointer(&self, target: Ty) -> Ty {
- (*self).build_pointer(target)
- }
- fn build_array(&self, element: Ty, count: usize) -> Ty {
- (*self).build_array(element, count)
- }
- fn build_vector(&self, element: Ty, length: VectorLength) -> Ty {
- (*self).build_vector(element, length)
- }
- fn build_struct(&self, members: &[Ty]) -> Ty {
- (*self).build_struct(members)
- }
- fn build_function(&self, arguments: &[Ty], return_type: Option<Ty>) -> Ty {
- (*self).build_function(arguments, return_type)
- }
-}
-
-/// trait for rust types that can be built using `TypeBuilder`
-pub trait BuildableType {
- /// build the type represented by `Self`
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty;
-}
-
-impl<T: BuildableType> BuildableType for UnsafeCell<T> {
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
- T::build(type_builder)
- }
-}
-
-mod hidden {
- pub trait ScalarBuildableTypeBase {}
-}
-
-impl<T: hidden::ScalarBuildableTypeBase> hidden::ScalarBuildableTypeBase for UnsafeCell<T> {}
-
-/// trait for rust types that can be an element of a vector and be built using `TypeBuilder`
-pub trait ScalarBuildableType: BuildableType + hidden::ScalarBuildableTypeBase {}
-
-impl<T: ScalarBuildableType> ScalarBuildableType for UnsafeCell<T> {}
-
-/// descriptor for members of types implementing `BuildableStruct`
-pub struct BuildableStructMemberDescriptor {
- /// name of member
- pub name: &'static str,
- /// index of member
- pub index: usize,
-}
-
-/// trait for structs that can be built using TypeBuilder
-/// implementing types are usually created using `buildable_struct!`
-pub trait BuildableStruct: BuildableType {
- /// get the list of members for `Self`
- fn get_members() -> &'static [BuildableStructMemberDescriptor];
- /// get the member for `Self` that is named `name`
- fn get_member_by_name(name: &str) -> &'static BuildableStructMemberDescriptor {
- for member in Self::get_members() {
- if name == member.name {
- return member;
- }
- }
- unreachable!("{} is not a member", name);
- }
-}
-
-macro_rules! build_basic_scalar {
- ($type:ty, $build_fn:ident) => {
- impl BuildableType for $type {
- fn build<'a, 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<T: BuildableType> 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<T: BuildableType> 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<T: BuildableType> BuildableType for NonNull<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 NonNull<T> {}
-
-impl<'b, T: BuildableType> ScalarBuildableType for NonNull<T> {}
-
-impl<T: BuildableType> BuildableType for Option<NonNull<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<NonNull<T>> {}
-
-impl<'b, T: BuildableType> ScalarBuildableType for Option<NonNull<T>> {}
-
-macro_rules! build_unit_function_type {
- ($($arguments:ident,)*) => {
- impl<$($arguments: BuildableType),*> BuildableType for Option<unsafe extern "C" fn($($arguments,)*)> {
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
- type_builder.build_function(&[$($arguments::build(type_builder),)*], None)
- }
- }
-
- impl<$($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option<unsafe extern "C" fn($($arguments,)*)> {}
-
- impl<$($arguments: BuildableType),*> ScalarBuildableType for Option<unsafe extern "C" fn($($arguments,)*)> {}
-
- 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<R: BuildableType, $($arguments: BuildableType),*> BuildableType for Option<unsafe extern "C" fn($($arguments,)*) -> R> {
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
- type_builder.build_function(&[$($arguments::build(type_builder),)*], Some(R::build(type_builder)))
- }
- }
-
- impl<R: BuildableType, $($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for Option<unsafe extern "C" fn($($arguments,)*) -> R> {}
-
- impl<R: BuildableType, $($arguments: BuildableType),*> ScalarBuildableType for Option<unsafe extern "C" fn($($arguments,)*) -> R> {}
-
- impl<R: BuildableType, $($arguments: BuildableType),*> 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<R: BuildableType, $($arguments: BuildableType),*> hidden::ScalarBuildableTypeBase for unsafe extern "C" fn($($arguments,)*) -> R {}
-
- impl<R: BuildableType, $($arguments: BuildableType),*> 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<T: BuildableType> 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<Element: ScalarBuildableType> {
- /// elements of the vector `Self`
- pub elements: [Element; $length],
- }
-
- impl<Element: ScalarBuildableType> Deref for $name<Element> {
- type Target = [Element; $length];
- fn deref(&self) -> &Self::Target {
- &self.elements
- }
- }
-
- impl<Element: ScalarBuildableType> DerefMut for $name<Element> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.elements
- }
- }
-
- impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
- type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
- }
- }
-
- impl<Element: ScalarBuildableType> Vector for $name<Element> {
- type Element = Element;
- const LENGTH: VectorLength = { VectorLength::Fixed { length: $length } };
- }
- };
-}
-
-macro_rules! build_variable_vector {
- ($name:ident, $base_length:expr) => {
- /// Vector of elements `Element`
- pub enum $name<Element: ScalarBuildableType> {
- #[doc(hidden)]
- __Dummy(__VectorNeverType, PhantomData<Element>),
- }
-
- impl<Element: ScalarBuildableType> BuildableType for $name<Element> {
- fn build<'a, Ty: Type<'a>, TB: TypeBuilder<'a, Ty>>(type_builder: &TB) -> Ty {
- type_builder.build_vector(Element::build(type_builder), Self::LENGTH)
- }
- }
-
- impl<Element: ScalarBuildableType> Vector for $name<Element> {
- type Element = Element;
- const LENGTH: VectorLength = {
- VectorLength::Variable {
- base_length: $base_length,
- }
- };
- }
- };
-}
-
-/// alternate name for `VecNx1`
-pub type VecN<Element> = VecNx1<Element>;
-
-build_fixed_vector!(Vec1, 1);
-build_fixed_vector!(Vec2, 2);
-build_fixed_vector!(Vec3, 3);
-build_fixed_vector!(Vec4, 4);
-build_fixed_vector!(Vec5, 5);
-build_fixed_vector!(Vec6, 6);
-build_fixed_vector!(Vec7, 7);
-build_fixed_vector!(Vec8, 8);
-build_fixed_vector!(Vec9, 9);
-build_fixed_vector!(Vec10, 10);
-build_fixed_vector!(Vec11, 11);
-build_fixed_vector!(Vec12, 12);
-build_fixed_vector!(Vec13, 13);
-build_fixed_vector!(Vec14, 14);
-build_fixed_vector!(Vec15, 15);
-build_fixed_vector!(Vec16, 16);
-build_variable_vector!(VecNx1, 1);
-build_variable_vector!(VecNx2, 2);
-build_variable_vector!(VecNx3, 3);
-build_variable_vector!(VecNx4, 4);
-build_variable_vector!(VecNx5, 5);
-build_variable_vector!(VecNx6, 6);
-build_variable_vector!(VecNx7, 7);
-build_variable_vector!(VecNx8, 8);
-build_variable_vector!(VecNx9, 9);
-build_variable_vector!(VecNx10, 10);
-build_variable_vector!(VecNx11, 11);
-build_variable_vector!(VecNx12, 12);
-build_variable_vector!(VecNx13, 13);
-build_variable_vector!(VecNx14, 14);
-build_variable_vector!(VecNx15, 15);
-build_variable_vector!(VecNx16, 16);
+++ /dev/null
-// 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<f32>,
- }
- }
-}
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"]}
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)]