diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 964d97d01..28f2a0db1 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -13,6 +13,7 @@ goblin = "0.0.24" libc = "0.2.60" nix = "0.14.1" capstone = { version = "0.6.0", optional = true } +structopt = "0.2.18" [dependencies.inkwell] git = "https://github.com/wasmerio/inkwell" diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 94b86e34d..763a7b348 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -10,6 +10,8 @@ use libc::c_char; use std::{ any::Any, ffi::{c_void, CString}, + fs::File, + io::Write, mem, ops::Deref, ptr::{self, NonNull}, @@ -177,6 +179,14 @@ impl LLVMBackend { .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(); + } + } + let callbacks = get_callbacks(); let mut module: *mut LLVMModule = ptr::null_mut(); diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 1e9a62182..4398b3548 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4639,6 +4639,10 @@ impl ModuleCodeGenerator 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(()); if cfg!(test) { pass_manager.add_verifier_pass(); @@ -4658,7 +4662,9 @@ impl ModuleCodeGenerator pass_manager.add_slp_vectorize_pass(); 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()); Ok((backend, Box::new(cache_gen))) diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index f18fc36b7..3b2356f3a 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -16,6 +16,9 @@ mod state; mod structs; mod trampolines; +use std::path::PathBuf; +use structopt::StructOpt; + pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator; pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator; @@ -27,3 +30,25 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen< backend::LLVMBackend, 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, + + /// Emit LLVM IR after optimization pipeline. + #[structopt(long = "backend-llvm-post-opt-ir", parse(from_os_str))] + post_opt_ir: Option, + + /// Emit LLVM generated native code object file. + #[structopt(long = "backend-llvm-object-file", parse(from_os_str))] + obj_file: Option, +} + +pub static mut GLOBAL_OPTIONS: CLIOptions = CLIOptions { + pre_opt_ir: None, + post_opt_ir: None, + obj_file: None, +}; diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index d42229836..a0b1f5634 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -155,6 +155,10 @@ struct Run { #[structopt(long = "cache-key", hidden = true)] cache_key: Option, + #[cfg(feature = "backend-llvm")] + #[structopt(flatten)] + backend_llvm_options: wasmer_llvm_backend::CLIOptions, + #[structopt(flatten)] 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))?; } + #[cfg(feature = "backend-llvm")] + { + if options.backend == Backend::LLVM { + unsafe { + wasmer_llvm_backend::GLOBAL_OPTIONS = options.backend_llvm_options.clone(); + } + } + } + let compiler: Box = match options.backend { #[cfg(feature = "backend-singlepass")] Backend::Singlepass => Box::new(SinglePassCompiler::new()),