Skip to content

Commit

Permalink
Merge #1040
Browse files Browse the repository at this point in the history
1040: Add the ability to pass backend specific options through CompilerConfig. r=nlewycky a=nlewycky

# Description
Add the ability to pass backend specific options through CompilerConfig.

Use this to replace wasmer_llvm_backend::GLOBAL_OPTIONS.

This adds a new item to CompilerConfig which can be any struct defined by a backend for backend specific configuration options. So far, we only implement the options that were previously in GLOBAL_OPTIONS, these move to wasmer.rs. The plan is to use these same callbacks for testing in llvm-backend-tests.

# Review

- [ ] Add a short description of the the change to the CHANGELOG.md file


Co-authored-by: Nick Lewycky <nick@wasmer.io>
  • Loading branch information
bors[bot] and nlewycky authored Dec 5, 2019
2 parents af7a368 + 8d3cf87 commit bf04864
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 46 deletions.
16 changes: 7 additions & 9 deletions lib/llvm-backend/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::stackmap::StackmapRegistry;
use crate::{
intrinsics::Intrinsics,
structs::{Callbacks, LLVMModule, LLVMResult, MemProtect},
LLVMCallbacks,
};
use inkwell::{
memory_buffer::MemoryBuffer,
Expand All @@ -13,8 +14,6 @@ use std::{
any::Any,
cell::RefCell,
ffi::{c_void, CString},
fs::File,
io::Write,
mem,
ops::Deref,
ptr::{self, NonNull},
Expand Down Expand Up @@ -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(),
Expand Down
21 changes: 17 additions & 4 deletions lib/llvm-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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(());
Expand Down Expand Up @@ -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();
Expand All @@ -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(())
}

Expand Down
26 changes: 9 additions & 17 deletions lib/llvm-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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>,

/// Emit LLVM IR after optimization pipeline.
pub post_opt_ir: Option<PathBuf>,
pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>;
pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer;

/// 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>>>,
}
17 changes: 16 additions & 1 deletion lib/runtime-core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
61 changes: 46 additions & 15 deletions src/bin/wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()))),
})))
}
}

Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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| {
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit bf04864

Please sign in to comment.