From 41287bd0f0558e49095ec2bd778b0dbc4ad8415e Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 16 Oct 2018 02:13:06 -0700 Subject: [PATCH] shader compiler test works! --- shader-compiler-llvm-7/build.rs | 32 ++++-- shader-compiler-llvm-7/src/backend.rs | 157 +++++++++++++++++++++----- shader-compiler/src/backend/mod.rs | 6 +- vulkan-driver/src/lib.rs | 1 + 4 files changed, 154 insertions(+), 42 deletions(-) diff --git a/shader-compiler-llvm-7/build.rs b/shader-compiler-llvm-7/build.rs index df7bceb..c45929b 100644 --- a/shader-compiler-llvm-7/build.rs +++ b/shader-compiler-llvm-7/build.rs @@ -126,7 +126,7 @@ fn make_config(llvm_dir: &Path) -> cmake::Config { env::var("TARGET").unwrap().split("-").next().unwrap(), ) .out_dir(llvm_dir) - .profile("RelWithDebInfo") + .profile("Debug") .always_configure(false); retval } @@ -150,8 +150,9 @@ fn get_libs, S: AsRef>( llvm_config_path: &Path, args: A, ) -> Vec { - llvm_config(&llvm_config_path, args) + 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 @@ -219,10 +220,10 @@ fn main() { "cargo:rustc-link-search=native={}", llvm_config(&llvm_config_path, Some("--libdir")) ); - let llvm_libs = get_libs(&llvm_config_path, Some("--libs")); - for lib in llvm_libs { - println!("cargo:rustc-link-lib=static={}", lib); - } + 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" @@ -290,9 +291,20 @@ void LLVM_InitializeNativeDisassembler(void) .unwrap() .write_to_file(out_dir.join("llvm_c.rs")) .unwrap(); - cc::Build::new() - .cpp(true) - .file(llvm_bindings_path) - .include(&include_dir) + let build_llvm_bindings = || { + let mut retval = cc::Build::new(); + retval + .cpp(true) + .file(&llvm_bindings_path) + .include(&include_dir); + retval + }; + build_llvm_bindings() + .cpp_link_stdlib(None) .compile("llvm_bindings"); + for lib in llvm_libs { + println!("cargo:rustc-link-lib={}", lib); + } + // build twice to get the c++ standard library linked after LLVM with llvm_bindings before LLVM + build_llvm_bindings().compile("llvm_bindings"); } diff --git a/shader-compiler-llvm-7/src/backend.rs b/shader-compiler-llvm-7/src/backend.rs index 63bb996..fb466d4 100644 --- a/shader-compiler-llvm-7/src/backend.rs +++ b/shader-compiler-llvm-7/src/backend.rs @@ -2,9 +2,13 @@ // Copyright 2018 Jacob Lifshay use llvm; use shader_compiler::backend; -use std::cell::Cell; +use std::cell::RefCell; +use std::collections::HashMap; 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; @@ -248,18 +252,18 @@ impl<'a> backend::Function<'a> for LLVM7Function { } pub struct LLVM7Context { - context: llvm::LLVMContextRef, - modules: Cell>, + context: Option>, + modules: ManuallyDrop>>, config: LLVM7CompilerConfig, } impl Drop for LLVM7Context { fn drop(&mut self) { unsafe { - for module in self.modules.get_mut().drain(..) { - llvm::LLVMDisposeModule(module); + ManuallyDrop::drop(&mut self.modules); + if let Some(context) = &mut self.context { + ManuallyDrop::drop(context); } - llvm::LLVMContextDispose(self.context); } } } @@ -277,24 +281,30 @@ impl<'a> backend::Context<'a> for LLVM7Context { type DetachedBuilder = LLVM7Builder; fn create_module(&self, name: &str) -> LLVM7Module { let name = CString::new(name).unwrap(); - let mut modules = self.modules.take(); - modules.reserve(1); // so we don't unwind without freeing the new module + let mut modules = self.modules.borrow_mut(); unsafe { - let module = llvm::LLVMModuleCreateWithNameInContext(name.as_ptr(), self.context); + let module = OwnedModule(llvm::LLVMModuleCreateWithNameInContext( + name.as_ptr(), + self.context.as_ref().unwrap().0, + )); + let module_ref = module.0; modules.push(module); - self.modules.set(modules); LLVM7Module { - context: self.context, - module, + context: self.context.as_ref().unwrap().0, + module: module_ref, } } } fn create_builder(&self) -> LLVM7Builder { - unsafe { LLVM7Builder(llvm::LLVMCreateBuilderInContext(self.context)) } + unsafe { + LLVM7Builder(llvm::LLVMCreateBuilderInContext( + self.context.as_ref().unwrap().0, + )) + } } fn create_type_builder(&self) -> LLVM7TypeBuilder { LLVM7TypeBuilder { - context: self.context, + context: self.context.as_ref().unwrap().0, variable_vector_length_multiplier: self.config.variable_vector_length_multiplier, } } @@ -338,6 +348,34 @@ impl<'a> backend::DetachedBuilder<'a> for LLVM7Builder { } } +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, @@ -439,6 +477,7 @@ fn initialize_native_target() { static ONCE: Once = ONCE_INIT; ONCE.call_once(|| unsafe { llvm::LLVM_InitializeNativeTarget(); + llvm::LLVM_InitializeNativeAsmPrinter(); llvm::LLVM_InitializeNativeAsmParser(); }); } @@ -463,21 +502,36 @@ impl backend::Compiler for LLVM7Compiler { ) -> Result>, U::Error> { unsafe { initialize_native_target(); - let context = LLVM7Context { - context: llvm::LLVMContextCreate(), - modules: Vec::new().into(), + 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)?; - for callable_function in callable_functions.values() { - assert_eq!( - llvm::LLVMGetGlobalParent(callable_function.function), - module.module - ); - } + 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(); @@ -513,15 +567,60 @@ impl backend::Compiler for LLVM7Compiler { assert!(!target_machine.0.is_null()); let orc_jit_stack = LLVM7OrcJITStack(llvm::LLVMOrcCreateInstance(target_machine.take())); - let mut orc_module_handle = 0; - llvm::LLVMOrcAddEagerlyCompiledIR( + let mut module_handle = 0; + if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcAddEagerlyCompiledIR( orc_jit_stack.0, - &mut orc_module_handle, - module.module, + &mut module_handle, + module.take(), Some(symbol_resolver_fn), null_mut(), - ); - unimplemented!() + ) { + return Err(U::create_error("compilation failed".into())); + } + let mut functions: HashMap<_, _> = HashMap::new(); + for (key, name) in callable_functions { + let mut address: llvm::LLVMOrcTargetAddress = mem::zeroed(); + if llvm::LLVMOrcErrSuccess != llvm::LLVMOrcGetSymbolAddressIn( + orc_jit_stack.0, + &mut address, + module_handle, + name.as_ptr(), + ) { + return Err(U::create_error(format!( + "function not found in compiled module: {:?}", + name + ))); + } + let address: Option = mem::transmute(address as usize); + if functions.insert(key, address.unwrap()).is_some() { + return Err(U::create_error(format!("duplicate function: {:?}", name))); + } + } + struct CompiledCode { + functions: HashMap, + orc_jit_stack: ManuallyDrop, + context: ManuallyDrop, + } + unsafe impl Send for CompiledCode {} + unsafe impl Sync for CompiledCode {} + impl Drop for CompiledCode { + fn drop(&mut self) { + unsafe { + ManuallyDrop::drop(&mut self.orc_jit_stack); + ManuallyDrop::drop(&mut self.context); + } + } + } + impl backend::CompiledCode for CompiledCode { + fn get(&self, key: &K) -> Option { + Some(*self.functions.get(key)?) + } + } + Ok(Box::new(CompiledCode { + functions, + orc_jit_stack: ManuallyDrop::new(orc_jit_stack), + context: context.context.take().unwrap(), + })) } } } diff --git a/shader-compiler/src/backend/mod.rs b/shader-compiler/src/backend/mod.rs index 0ba1b6c..f3418b8 100644 --- a/shader-compiler/src/backend/mod.rs +++ b/shader-compiler/src/backend/mod.rs @@ -181,7 +181,7 @@ pub trait Context<'a>: Sized { } /// inputs to the final compilation -pub struct CompileInputs<'a, C: Context<'a>, K: Hash + Eq + Send + Sync> { +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` @@ -189,7 +189,7 @@ pub struct CompileInputs<'a, C: Context<'a>, K: Hash + Eq + Send + Sync> { } /// the final compiled code -pub trait CompiledCode: Send + Sync { +pub trait CompiledCode: Send + Sync { /// get a function in the final compiled code. /// the returned function needs to be cast to the correct type and /// `Self` needs to still exist while the returned function exists @@ -199,7 +199,7 @@ pub trait CompiledCode: Send + Sync { /// 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; + type FunctionKey: Hash + Eq + Send + Sync + 'static; /// the user's error type type Error; /// create an instance of `Error` diff --git a/vulkan-driver/src/lib.rs b/vulkan-driver/src/lib.rs index 9b38b55..66fa5a7 100644 --- a/vulkan-driver/src/lib.rs +++ b/vulkan-driver/src/lib.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: LGPL-2.1-or-later // Copyright 2018 Jacob Lifshay +#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))] #[macro_use] extern crate enum_map; #[cfg(unix)] -- 2.30.2