Add support for backend flags. Backend flags are opaque to src/bin/wasmer.rs.

Use them to implement three features in the LLVM backend, getting a valid ELF object file, the post-optimization LLVM IR and the pre-optimization LLVM IR.

Presently they are also global to the backend which is not ideal.
This commit is contained in:
Nick Lewycky
2019-08-08 16:05:17 -07:00
parent 77fe15db31
commit b2c4501357
5 changed files with 56 additions and 1 deletions

View File

@ -13,6 +13,7 @@ goblin = "0.0.24"
libc = "0.2.60" libc = "0.2.60"
nix = "0.14.1" nix = "0.14.1"
capstone = { version = "0.6.0", optional = true } capstone = { version = "0.6.0", optional = true }
structopt = "0.2.18"
[dependencies.inkwell] [dependencies.inkwell]
git = "https://github.com/wasmerio/inkwell" git = "https://github.com/wasmerio/inkwell"

View File

@ -10,6 +10,8 @@ use libc::c_char;
use std::{ use std::{
any::Any, any::Any,
ffi::{c_void, CString}, ffi::{c_void, CString},
fs::File,
io::Write,
mem, mem,
ops::Deref, ops::Deref,
ptr::{self, NonNull}, ptr::{self, NonNull},
@ -177,6 +179,14 @@ impl LLVMBackend {
.unwrap(); .unwrap();
let mem_buf_slice = memory_buffer.as_slice(); 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();
}
}
let callbacks = get_callbacks(); let callbacks = get_callbacks();
let mut module: *mut LLVMModule = ptr::null_mut(); let mut module: *mut LLVMModule = ptr::null_mut();

View File

@ -4639,6 +4639,10 @@ impl ModuleCodeGenerator<LLVMFunctionCodeGenerator, LLVMBackend, CodegenError>
self.intrinsics.as_ref().unwrap(), self.intrinsics.as_ref().unwrap(),
); );
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } {
self.module.print_to_file(path).unwrap();
}
let pass_manager = PassManager::create(()); let pass_manager = PassManager::create(());
if cfg!(test) { if cfg!(test) {
pass_manager.add_verifier_pass(); pass_manager.add_verifier_pass();
@ -4658,7 +4662,9 @@ impl ModuleCodeGenerator<LLVMFunctionCodeGenerator, LLVMBackend, CodegenError>
pass_manager.add_slp_vectorize_pass(); pass_manager.add_slp_vectorize_pass();
pass_manager.run_on(&self.module); pass_manager.run_on(&self.module);
// self.module.print_to_stderr(); if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } {
self.module.print_to_file(path).unwrap();
}
let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap()); let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap());
Ok((backend, Box::new(cache_gen))) Ok((backend, Box::new(cache_gen)))

View File

@ -16,6 +16,9 @@ mod state;
mod structs; mod structs;
mod trampolines; mod trampolines;
use std::path::PathBuf;
use structopt::StructOpt;
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator; pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator; pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
@ -27,3 +30,25 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen<
backend::LLVMBackend, backend::LLVMBackend,
code::CodegenError, code::CodegenError,
>; >;
#[derive(Debug, StructOpt, Clone)]
/// LLVM backend flags.
pub struct CLIOptions {
/// Emit LLVM IR before optimization pipeline.
#[structopt(long = "backend-llvm-pre-opt-ir", parse(from_os_str))]
pre_opt_ir: Option<PathBuf>,
/// Emit LLVM IR after optimization pipeline.
#[structopt(long = "backend-llvm-post-opt-ir", parse(from_os_str))]
post_opt_ir: Option<PathBuf>,
/// Emit LLVM generated native code object file.
#[structopt(long = "backend-llvm-object-file", parse(from_os_str))]
obj_file: Option<PathBuf>,
}
pub static mut GLOBAL_OPTIONS: CLIOptions = CLIOptions {
pre_opt_ir: None,
post_opt_ir: None,
obj_file: None,
};

View File

@ -155,6 +155,10 @@ struct Run {
#[structopt(long = "cache-key", hidden = true)] #[structopt(long = "cache-key", hidden = true)]
cache_key: Option<String>, cache_key: Option<String>,
#[cfg(feature = "backend-llvm")]
#[structopt(flatten)]
backend_llvm_options: wasmer_llvm_backend::CLIOptions,
#[structopt(flatten)] #[structopt(flatten)]
features: PrestandardFeatures, features: PrestandardFeatures,
@ -356,6 +360,15 @@ 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))?;
} }
#[cfg(feature = "backend-llvm")]
{
if options.backend == Backend::LLVM {
unsafe {
wasmer_llvm_backend::GLOBAL_OPTIONS = options.backend_llvm_options.clone();
}
}
}
let compiler: Box<dyn Compiler> = match options.backend { let compiler: Box<dyn Compiler> = match options.backend {
#[cfg(feature = "backend-singlepass")] #[cfg(feature = "backend-singlepass")]
Backend::Singlepass => Box::new(SinglePassCompiler::new()), Backend::Singlepass => Box::new(SinglePassCompiler::new()),