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