Skip to content

Commit

Permalink
Merge pull request #20 from mewz-project/option_output_path
Browse files Browse the repository at this point in the history
option for output path
  • Loading branch information
ainozaki authored Feb 15, 2024
2 parents fb600b9 + de055ca commit 5280faf
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 60 deletions.
47 changes: 24 additions & 23 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,42 @@ use crate::inkwell::init_inkwell;
use crate::insts::control::UnreachableReason;
use crate::section::translate_module;
use anyhow::{anyhow, Context, Result};
use clap::Parser;
use inkwell::{context, module::Module, passes::PassManager, targets};
use std::path;
use wat;

#[derive(Parser, Debug)]
pub struct Args {
pub input_file: String,

#[arg(short, long, default_value = "./wasm.o")]
pub output_file: String,
}

/// Receive a path to a Wasm binary or WAT and compile it into ELF binary.
pub fn compile_wasm_from_file(filepath: &str) -> Result<()> {
pub fn compile_wasm_from_file(args: &Args) -> Result<()> {
// Load bytes as either *.wat or *.wasm
log::info!("input: {}", filepath);
let buf: Vec<u8> = std::fs::read(filepath).expect("error read file");
log::info!("input: {}", args.input_file);
let buf: Vec<u8> = std::fs::read(args.input_file.as_str()).expect("error read file");

// If input is *.wat, convert it into *wasm
// If input is *.wasm, do nothing
let wasm = wat::parse_bytes(&buf).expect("error translate wat");
assert!(wasm.starts_with(b"\0asm"));

// TODO: make option to output wasm
/*
// Output wasm
let pathbuf = PathBuf::from(filepath);
let filestem = pathbuf
.file_stem()
.expect("error extract file stem")
.to_string_lossy()
.into_owned();
let wasm_path = format!("tests/wasm/{}.wasm", filestem);
let mut file = File::create(wasm_path)?;
file.write_all(&wasm)?;
file.flush()?;
*/
compile_wasm(&wasm)
compile_wasm(&wasm, args)
}

/// Receive a Wasm binary and compile it into ELF binary.
pub fn compile_wasm(wasm: &[u8]) -> Result<()> {
pub fn compile_wasm(wasm: &[u8], args: &Args) -> Result<()> {
// Prepare inkwell (Rust-wrapper of LLVM) instances
let context = context::Context::create();
let module = context.create_module("wasker_module");
let builder = context.create_builder();
let (inkwell_types, inkwell_insts) = init_inkwell(&context, &module);
let mut environment = Environment {
output_file: args.output_file.as_str(),
context: &context,
module: &module,
builder,
Expand Down Expand Up @@ -112,19 +109,23 @@ pub fn compile_wasm(wasm: &[u8]) -> Result<()> {
}

fn output_elf(environment: Environment) -> Result<()> {
log::info!("write to wasm.ll");
let ll_path = path::Path::new("./wasm.ll");
let obj_path = path::Path::new(environment.output_file);

log::info!("write to {}", ll_path.display());
environment
.module
.print_to_file(std::path::Path::new("./wasm.ll"))
.print_to_file(ll_path.to_str().expect("error ll_path"))
.map_err(|e| anyhow!(e.to_string()))
.context("fail print_to_file")?;
log::info!("write to wasm.o, it may take a while");

log::info!("write to {}, it may take a while", obj_path.display());
get_host_target_machine()
.expect("error get_host_target_machine")
.write_to_file(
environment.module,
targets::FileType::Object,
std::path::Path::new("./wasm.o"),
std::path::Path::new(obj_path.to_str().expect("error obj_path")),
)
.map_err(|e| anyhow!(e.to_string()))
.context("fail write_to_file")?;
Expand Down
3 changes: 3 additions & 0 deletions src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub enum Global<'a> {
}

pub struct Environment<'a, 'b> {
// Output dir
pub output_file: &'b str,

// Inkwell code generator
pub context: &'a Context,
pub module: &'b Module<'a>,
Expand Down
9 changes: 2 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ use anyhow::Result;
use clap::Parser;
use wasker::compiler;

#[derive(Parser, Debug)]
struct Args {
file: String,
}

fn main() -> Result<()> {
// init logger
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let args = Args::parse();
let args = compiler::Args::parse();

// Compile Wasm and output ELF
compiler::compile_wasm_from_file(&args.file)?;
compiler::compile_wasm_from_file(&args)?;

Ok(())
}
80 changes: 66 additions & 14 deletions tests/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,130 @@ use wasker::compiler;

#[test]
fn example() {
let wat = "./tests/wat/example.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let wat = "./tests/wat/block.wat";
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn block() {
let wat = "./tests/wat/block.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn ret() {
let wat = "./tests/wat/return.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn call() {
let wat = "./tests/wat/call.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn call_indirect() {
let wat = "./tests/wat/call_indirect.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn select() {
let wat = "./tests/wat/select.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn br() {
let wat = "./tests/wat/br.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn br_table() {
let wat = "./tests/wat/br_table.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn br_if() {
let wat = "./tests/wat/br_if.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn iff() {
let wat = "./tests/wat/if.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn loopp() {
let wat = "./tests/wat/loop.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn switch() {
let wat = "./tests/wat/switch.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn bulk() {
let wat = "./tests/wat/bulk.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}
12 changes: 10 additions & 2 deletions tests/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ use wasker::compiler;
#[test]
fn local_get() {
let wat = "./tests/wat/local_get.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn global() {
let wat = "./tests/wat/global.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}
42 changes: 35 additions & 7 deletions tests/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,69 @@ use wasker::compiler;
#[test]
fn memory_size() {
let wat = "./tests/wat/memory_size.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn memory_copy() {
let wat = "./tests/wat/memory_copy.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn memory_fill() {
let wat = "./tests/wat/memory_fill.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn endianness() {
let wat = "./tests/wat/endianness.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn address32() {
let wat = "./tests/wat/address32.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn address64() {
let wat = "./tests/wat/address64.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}

#[test]
fn align() {
let wat = "./tests/wat/align.wat";
compiler::compile_wasm_from_file(wat).expect("fail compile");
let args = compiler::Args {
input_file: wat.to_string(),
output_file: "/tmp/wasm.o".to_string(),
};
compiler::compile_wasm_from_file(&args).expect("fail compile");
}
Loading

0 comments on commit 5280faf

Please sign in to comment.