Add support for emitting code with a single return at the end. (#153)

This also enables testing of the wasmtests tests.

This also updates for wabt updating to the official "wat" filename
extension, as opposed to "wast".
This commit is contained in:
Dan Gohman
2017-09-12 13:27:36 -07:00
committed by GitHub
parent 2e046d68ce
commit 1ab207b93c
15 changed files with 154 additions and 38 deletions

View File

@@ -1,18 +1,24 @@
extern crate cton_wasm;
extern crate cretonne;
extern crate tempdir;
use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
use std::path::PathBuf;
use std::borrow::Borrow;
use std::fs::File;
use std::error::Error;
use std::io;
use std::str;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::Command;
use std::fs;
use cretonne::ir;
use cretonne::ir::entities::AnyEntity;
use cretonne::isa::TargetIsa;
use cretonne::isa::{self, TargetIsa};
use cretonne::settings::{self, Configurable};
use cretonne::verifier;
use tempdir::TempDir;
#[test]
fn testsuite() {
@@ -23,13 +29,29 @@ fn testsuite() {
paths.sort_by_key(|dir| dir.path());
for path in paths {
let path = path.path();
match handle_module(path) {
Ok(()) => (),
Err(message) => println!("{}", message),
};
handle_module(path, None);
}
}
#[test]
fn return_at_end() {
let mut flag_builder = settings::builder();
flag_builder.enable("return_at_end").unwrap();
let flags = settings::Flags::new(&flag_builder);
// We don't care about the target itself here, so just pick one arbitrarily.
let isa = match isa::lookup("riscv") {
Err(_) => {
println!("riscv target not found; disabled test return_at_end.wat");
return;
}
Ok(isa_builder) => isa_builder.finish(flags),
};
handle_module(
PathBuf::from("../../wasmtests/return_at_end.wat"),
Some(isa.borrow()),
);
}
fn read_wasm_file(path: PathBuf) -> Result<Vec<u8>, io::Error> {
let mut buf: Vec<u8> = Vec::new();
let file = File::open(path)?;
@@ -38,44 +60,80 @@ fn read_wasm_file(path: PathBuf) -> Result<Vec<u8>, io::Error> {
Ok(buf)
}
fn handle_module(path: PathBuf) -> Result<(), String> {
fn handle_module(path: PathBuf, isa: Option<&TargetIsa>) {
let data = match path.extension() {
None => {
return Err(String::from("the file extension is not wasm or wast"));
panic!("the file extension is not wasm or wat");
}
Some(ext) => {
match ext.to_str() {
Some("wasm") => {
match read_wasm_file(path.clone()) {
Ok(data) => data,
Err(err) => panic!("error reading wasm file: {}", err.description()),
}
}
Some("wat") => {
let tmp_dir = TempDir::new("cretonne-wasm").unwrap();
let file_path = tmp_dir.path().join("module.wasm");
File::create(file_path.clone()).unwrap();
let result_output = Command::new("wat2wasm")
.arg(path.clone())
.arg("-o")
.arg(file_path.to_str().unwrap())
.output();
match result_output {
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
println!(
"wat2wasm not found; disabled test {}",
path.to_str().unwrap()
);
return;
}
panic!("error convering wat file: {}", e.description());
}
Ok(output) => {
if !output.status.success() {
panic!(
"error running wat2wasm: {}",
str::from_utf8(&output.stderr).expect(
"wat2wasm's error message should be valid UTF-8",
)
);
}
}
}
match read_wasm_file(file_path) {
Ok(data) => data,
Err(err) => {
return Err(String::from(err.description()));
panic!("error reading converted wasm file: {}", err.description());
}
}
}
None | Some(&_) => {
return Err(String::from("the file extension is not wasm or wast"));
}
None | Some(&_) => panic!("the file extension is not wasm or wat"),
}
}
};
let mut dummy_runtime = DummyRuntime::new();
let mut dummy_runtime = match isa {
Some(isa) => DummyRuntime::with_flags(isa.flags().clone()),
None => DummyRuntime::default(),
};
let translation = {
let runtime: &mut WasmRuntime = &mut dummy_runtime;
match translate_module(&data, runtime) {
Ok(x) => x,
Err(string) => {
return Err(string);
panic!(string);
}
}
};
for func in &translation.functions {
match verifier::verify_function(func, None) {
match verifier::verify_function(func, isa) {
Ok(()) => (),
Err(err) => return Err(pretty_verifier_error(func, None, err)),
Err(err) => panic!(pretty_verifier_error(func, isa, err)),
}
}
Ok(())
}