mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 22:21:32 +00:00
Add the ability to pass backend specific options through CompilerConfig.
Use this to replace wasmer_llvm_backend::GLOBAL_OPTIONS.
This commit is contained in:
@ -2,6 +2,7 @@ use super::stackmap::StackmapRegistry;
|
|||||||
use crate::{
|
use crate::{
|
||||||
intrinsics::Intrinsics,
|
intrinsics::Intrinsics,
|
||||||
structs::{Callbacks, LLVMModule, LLVMResult, MemProtect},
|
structs::{Callbacks, LLVMModule, LLVMResult, MemProtect},
|
||||||
|
LLVMCallbacks,
|
||||||
};
|
};
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
memory_buffer::MemoryBuffer,
|
memory_buffer::MemoryBuffer,
|
||||||
@ -13,8 +14,6 @@ use std::{
|
|||||||
any::Any,
|
any::Any,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
ffi::{c_void, CString},
|
ffi::{c_void, CString},
|
||||||
fs::File,
|
|
||||||
io::Write,
|
|
||||||
mem,
|
mem,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
ptr::{self, NonNull},
|
ptr::{self, NonNull},
|
||||||
@ -176,23 +175,22 @@ impl LLVMBackend {
|
|||||||
_stackmaps: &StackmapRegistry,
|
_stackmaps: &StackmapRegistry,
|
||||||
_module_info: &ModuleInfo,
|
_module_info: &ModuleInfo,
|
||||||
target_machine: &TargetMachine,
|
target_machine: &TargetMachine,
|
||||||
|
llvm_callbacks: &Option<Rc<RefCell<dyn LLVMCallbacks>>>,
|
||||||
) -> (Self, LLVMCache) {
|
) -> (Self, LLVMCache) {
|
||||||
let memory_buffer = target_machine
|
let memory_buffer = target_machine
|
||||||
.write_to_memory_buffer(&module.borrow_mut(), FileType::Object)
|
.write_to_memory_buffer(&module.borrow_mut(), FileType::Object)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mem_buf_slice = memory_buffer.as_slice();
|
|
||||||
|
|
||||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.obj_file } {
|
if let Some(callbacks) = llvm_callbacks {
|
||||||
let mut file = File::create(path).unwrap();
|
callbacks
|
||||||
let mut pos = 0;
|
.borrow_mut()
|
||||||
while pos < mem_buf_slice.len() {
|
.obj_memory_buffer_callback(&memory_buffer);
|
||||||
pos += file.write(&mem_buf_slice[pos..]).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let callbacks = get_callbacks();
|
let callbacks = get_callbacks();
|
||||||
let mut module: *mut LLVMModule = ptr::null_mut();
|
let mut module: *mut LLVMModule = ptr::null_mut();
|
||||||
|
|
||||||
|
let mem_buf_slice = memory_buffer.as_slice();
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
module_load(
|
module_load(
|
||||||
mem_buf_slice.as_ptr(),
|
mem_buf_slice.as_ptr(),
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic},
|
stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic},
|
||||||
state::{ControlFrame, ExtraInfo, IfElseState, State},
|
state::{ControlFrame, ExtraInfo, IfElseState, State},
|
||||||
trampolines::generate_trampolines,
|
trampolines::generate_trampolines,
|
||||||
|
LLVMBackendConfig, LLVMCallbacks,
|
||||||
};
|
};
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
builder::Builder,
|
builder::Builder,
|
||||||
@ -877,6 +878,7 @@ pub struct LLVMModuleCodeGenerator<'ctx> {
|
|||||||
stackmaps: Rc<RefCell<StackmapRegistry>>,
|
stackmaps: Rc<RefCell<StackmapRegistry>>,
|
||||||
track_state: bool,
|
track_state: bool,
|
||||||
target_machine: TargetMachine,
|
target_machine: TargetMachine,
|
||||||
|
llvm_callbacks: Option<Rc<RefCell<dyn LLVMCallbacks>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LLVMFunctionCodeGenerator<'ctx> {
|
pub struct LLVMFunctionCodeGenerator<'ctx> {
|
||||||
@ -8513,6 +8515,7 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
|
|||||||
stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())),
|
stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())),
|
||||||
track_state: false,
|
track_state: false,
|
||||||
target_machine,
|
target_machine,
|
||||||
|
llvm_callbacks: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8654,8 +8657,10 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
|
|||||||
message: format!("trampolines generation error: {:?}", e),
|
message: format!("trampolines generation error: {:?}", e),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } {
|
if let Some(ref mut callbacks) = self.llvm_callbacks {
|
||||||
self.module.borrow_mut().print_to_file(path).unwrap();
|
callbacks
|
||||||
|
.borrow_mut()
|
||||||
|
.preopt_ir_callback(&*self.module.borrow_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
let pass_manager = PassManager::create(());
|
let pass_manager = PassManager::create(());
|
||||||
@ -8695,8 +8700,10 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
|
|||||||
pass_manager.add_early_cse_pass();
|
pass_manager.add_early_cse_pass();
|
||||||
|
|
||||||
pass_manager.run_on(&*self.module.borrow_mut());
|
pass_manager.run_on(&*self.module.borrow_mut());
|
||||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } {
|
if let Some(ref mut callbacks) = self.llvm_callbacks {
|
||||||
self.module.borrow_mut().print_to_file(path).unwrap();
|
callbacks
|
||||||
|
.borrow_mut()
|
||||||
|
.postopt_ir_callback(&*self.module.borrow_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
let stackmaps = self.stackmaps.borrow();
|
let stackmaps = self.stackmaps.borrow();
|
||||||
@ -8707,12 +8714,18 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
|
|||||||
&*stackmaps,
|
&*stackmaps,
|
||||||
module_info,
|
module_info,
|
||||||
&self.target_machine,
|
&self.target_machine,
|
||||||
|
&mut self.llvm_callbacks,
|
||||||
);
|
);
|
||||||
Ok((backend, Box::new(cache_gen)))
|
Ok((backend, Box::new(cache_gen)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> {
|
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> {
|
||||||
self.track_state = config.track_state;
|
self.track_state = config.track_state;
|
||||||
|
if let Some(backend_compiler_config) = &config.backend_specific_config {
|
||||||
|
if let Some(llvm_config) = backend_compiler_config.get_specific::<LLVMBackendConfig>() {
|
||||||
|
self.llvm_callbacks = llvm_config.callbacks.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,6 @@ mod state;
|
|||||||
mod structs;
|
mod structs;
|
||||||
mod trampolines;
|
mod trampolines;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
|
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
|
||||||
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
|
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
|
||||||
|
|
||||||
@ -35,21 +33,15 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen<
|
|||||||
code::CodegenError,
|
code::CodegenError,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>;
|
||||||
/// LLVM backend flags.
|
pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer;
|
||||||
pub struct LLVMOptions {
|
|
||||||
/// Emit LLVM IR before optimization pipeline.
|
|
||||||
pub pre_opt_ir: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Emit LLVM IR after optimization pipeline.
|
pub trait LLVMCallbacks: std::any::Any + 'static {
|
||||||
pub post_opt_ir: Option<PathBuf>,
|
fn preopt_ir_callback(&mut self, module: &InkwellModule);
|
||||||
|
fn postopt_ir_callback(&mut self, module: &InkwellModule);
|
||||||
/// Emit LLVM generated native code object file.
|
fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer);
|
||||||
pub obj_file: Option<PathBuf>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut GLOBAL_OPTIONS: LLVMOptions = LLVMOptions {
|
pub struct LLVMBackendConfig {
|
||||||
pre_opt_ir: None,
|
pub callbacks: Option<std::rc::Rc<std::cell::RefCell<dyn LLVMCallbacks>>>,
|
||||||
post_opt_ir: None,
|
}
|
||||||
obj_file: None,
|
|
||||||
};
|
|
||||||
|
@ -200,6 +200,19 @@ pub struct Features {
|
|||||||
pub threads: bool,
|
pub threads: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use this to point to a compiler config struct provided by the backend.
|
||||||
|
/// The backend struct must support runtime reflection with `Any`, which is any
|
||||||
|
/// struct that does not contain a non-`'static` reference.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BackendCompilerConfig(pub Box<dyn Any + 'static>);
|
||||||
|
|
||||||
|
impl BackendCompilerConfig {
|
||||||
|
/// Obtain the backend-specific compiler config struct.
|
||||||
|
pub fn get_specific<T: 'static>(&self) -> Option<&T> {
|
||||||
|
self.0.downcast_ref::<T>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration data for the compiler
|
/// Configuration data for the compiler
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct CompilerConfig {
|
pub struct CompilerConfig {
|
||||||
@ -210,10 +223,12 @@ pub struct CompilerConfig {
|
|||||||
pub track_state: bool,
|
pub track_state: bool,
|
||||||
pub features: Features,
|
pub features: Features,
|
||||||
|
|
||||||
// target info used by LLVM
|
// Target info. Presently only supported by LLVM.
|
||||||
pub triple: Option<String>,
|
pub triple: Option<String>,
|
||||||
pub cpu_name: Option<String>,
|
pub cpu_name: Option<String>,
|
||||||
pub cpu_features: Option<String>,
|
pub cpu_features: Option<String>,
|
||||||
|
|
||||||
|
pub backend_specific_config: Option<BackendCompilerConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Compiler {
|
pub trait Compiler {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
)]
|
)]
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{metadata, read_to_string, File};
|
use std::fs::{metadata, read_to_string, File};
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -17,14 +18,15 @@ use std::path::PathBuf;
|
|||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use structopt::{clap, StructOpt};
|
use structopt::{clap, StructOpt};
|
||||||
|
|
||||||
use wasmer::*;
|
use wasmer::*;
|
||||||
#[cfg(feature = "backend-cranelift")]
|
#[cfg(feature = "backend-cranelift")]
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
#[cfg(feature = "backend-llvm")]
|
#[cfg(feature = "backend-llvm")]
|
||||||
use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions};
|
use wasmer_llvm_backend::{
|
||||||
|
InkwellMemoryBuffer, InkwellModule, LLVMBackendConfig, LLVMCallbacks, LLVMCompiler,
|
||||||
|
};
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
cache::{Cache as BaseCache, FileSystemCache, WasmHash},
|
cache::{Cache as BaseCache, FileSystemCache, WasmHash},
|
||||||
Value, VERSION,
|
Value, VERSION,
|
||||||
@ -40,6 +42,11 @@ use wasmer_runtime_core::{
|
|||||||
#[cfg(feature = "wasi")]
|
#[cfg(feature = "wasi")]
|
||||||
use wasmer_wasi;
|
use wasmer_wasi;
|
||||||
|
|
||||||
|
#[cfg(feature = "backend-llvm")]
|
||||||
|
use std::{cell::RefCell, io::Write, rc::Rc};
|
||||||
|
#[cfg(feature = "backend-llvm")]
|
||||||
|
use wasmer_runtime_core::backend::BackendCompilerConfig;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(name = "wasmer", about = "Wasm execution runtime.", author)]
|
#[structopt(name = "wasmer", about = "Wasm execution runtime.", author)]
|
||||||
/// The options for the wasmer Command Line Interface
|
/// The options for the wasmer Command Line Interface
|
||||||
@ -486,6 +493,32 @@ fn execute_wasi(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend-llvm")]
|
||||||
|
impl LLVMCallbacks for LLVMCLIOptions {
|
||||||
|
fn preopt_ir_callback(&mut self, module: &InkwellModule) {
|
||||||
|
if let Some(filename) = &self.pre_opt_ir {
|
||||||
|
module.print_to_file(filename).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postopt_ir_callback(&mut self, module: &InkwellModule) {
|
||||||
|
if let Some(filename) = &self.post_opt_ir {
|
||||||
|
module.print_to_file(filename).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer) {
|
||||||
|
if let Some(filename) = &self.obj_file {
|
||||||
|
let mem_buf_slice = memory_buffer.as_slice();
|
||||||
|
let mut file = File::create(filename).unwrap();
|
||||||
|
let mut pos = 0;
|
||||||
|
while pos < mem_buf_slice.len() {
|
||||||
|
pos += file.write(&mem_buf_slice[pos..]).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute a wasm/wat file
|
/// Execute a wasm/wat file
|
||||||
fn execute_wasm(options: &Run) -> Result<(), String> {
|
fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||||
let disable_cache = options.disable_cache;
|
let disable_cache = options.disable_cache;
|
||||||
@ -558,22 +591,17 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
.map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?;
|
.map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let compiler: Box<dyn Compiler> = match get_compiler_by_backend(options.backend, options) {
|
let compiler: Box<dyn Compiler> = get_compiler_by_backend(options.backend, options)
|
||||||
Some(x) => x,
|
.ok_or_else(|| "the requested backend is not enabled")?;
|
||||||
None => return Err("the requested backend is not enabled".into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut backend_specific_config = None;
|
||||||
#[cfg(feature = "backend-llvm")]
|
#[cfg(feature = "backend-llvm")]
|
||||||
{
|
{
|
||||||
if options.backend == Backend::LLVM {
|
if options.backend == Backend::LLVM {
|
||||||
let options = options.backend_llvm_options.clone();
|
backend_specific_config = Some(BackendCompilerConfig(Box::new(LLVMBackendConfig {
|
||||||
unsafe {
|
callbacks: Some(Rc::new(RefCell::new(options.backend_llvm_options.clone()))),
|
||||||
wasmer_llvm_backend::GLOBAL_OPTIONS = LLVMOptions {
|
})))
|
||||||
pre_opt_ir: options.pre_opt_ir,
|
|
||||||
post_opt_ir: options.post_opt_ir,
|
|
||||||
obj_file: options.obj_file,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,6 +626,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
enforce_stack_check: true,
|
enforce_stack_check: true,
|
||||||
track_state,
|
track_state,
|
||||||
features: options.features.into_backend_features(),
|
features: options.features.into_backend_features(),
|
||||||
|
backend_specific_config,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&*compiler,
|
&*compiler,
|
||||||
@ -610,6 +639,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
symbol_map: em_symbol_map.clone(),
|
symbol_map: em_symbol_map.clone(),
|
||||||
track_state,
|
track_state,
|
||||||
features: options.features.into_backend_features(),
|
features: options.features.into_backend_features(),
|
||||||
|
backend_specific_config,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&*compiler,
|
&*compiler,
|
||||||
@ -625,7 +655,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
let mut cache = unsafe {
|
let mut cache = unsafe {
|
||||||
FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))?
|
FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))?
|
||||||
};
|
};
|
||||||
let mut load_cache_key = || -> Result<_, String> {
|
let load_cache_key = || -> Result<_, String> {
|
||||||
if let Some(ref prehashed_cache_key) = options.cache_key {
|
if let Some(ref prehashed_cache_key) = options.cache_key {
|
||||||
if let Ok(module) =
|
if let Ok(module) =
|
||||||
WasmHash::decode(prehashed_cache_key).and_then(|prehashed_key| {
|
WasmHash::decode(prehashed_cache_key).and_then(|prehashed_key| {
|
||||||
@ -655,6 +685,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
symbol_map: em_symbol_map.clone(),
|
symbol_map: em_symbol_map.clone(),
|
||||||
track_state,
|
track_state,
|
||||||
features: options.features.into_backend_features(),
|
features: options.features.into_backend_features(),
|
||||||
|
backend_specific_config,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&*compiler,
|
&*compiler,
|
||||||
|
Reference in New Issue
Block a user