Files
wasmtime/cranelift/src/clif-util.rs
Alex Crichton 3a13f79b66 Try to reduce CI times with a Rust *.wat parser (#1332)
This commit moves the cranelift tests and tools from the `wabt` crate on
crates.io (which compiles the wabt C++ codebase) to the `wat` crate on
crates.io which is a Rust parser for the `*.wat` format. This was
motivated by me noticing that release builds on Windows are ~5 minutes
longer than Linux builds, and local timing graphs showed that `wabt-sys`
was by far the longest build step in the build process.

This commit changes the `clif-util` binary where the `--enable-simd`
flag is no longer respected with the text format as input, since the
`wat` crate has no feature gating. This was already sort of not
respected, though, since `--enable-simd` wasn't consulted for binary
inputs which `clif-util` supports as well. If this isn't ok though then
it should be ok to close this PR!
2020-01-10 14:32:16 -08:00

336 lines
10 KiB
Rust
Executable File

#![deny(trivial_numeric_casts)]
#![warn(unused_import_braces, unstable_features, unused_extern_crates)]
#![cfg_attr(
feature = "cargo-clippy",
warn(
clippy::float_arithmetic,
clippy::mut_mut,
clippy::nonminimal_bool,
clippy::option_map_unwrap_or,
clippy::option_map_unwrap_or_else,
clippy::unicode_not_nfc,
clippy::use_self
)
)]
use clap::{App, Arg, SubCommand};
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
use cranelift_codegen::VERSION;
use std::io::{self, Write};
use std::option::Option;
use std::process;
mod bugpoint;
mod cat;
mod compile;
mod disasm;
mod print_cfg;
mod run;
mod utils;
#[cfg(feature = "wasm")]
mod wasm;
/// A command either succeeds or fails with an error message.
pub type CommandResult = Result<(), String>;
fn add_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("file")
.default_value("-")
.multiple(true)
.value_name("file")
.help("Specify file(s) to be used for test. Defaults to reading from stdin.")
}
fn add_single_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("single-file")
.required(true)
.value_name("single-file")
.help("Specify a file to be used. Use '-' for stdin.")
}
fn add_pass_arg<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("pass")
.required(true)
.multiple(true)
.value_name("pass")
.help("Specify pass(s) to be run on test file")
}
fn add_verbose_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("verbose").short("v").help("Be more verbose")
}
fn add_time_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("time-passes")
.short("T")
.help("Print pass timing report for test")
}
fn add_size_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("print-size")
.short("X")
.help("Print bytecode size")
}
fn add_disasm_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("disasm")
.long("disasm")
.short("D")
.help("Print machine code disassembly")
}
fn add_set_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("set")
.long("set")
.takes_value(true)
.multiple(true)
.help("Configure Cranelift settings")
}
fn add_target_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("target")
.takes_value(true)
.long("target")
.help("Specify the Cranelift target")
}
fn add_print_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("print")
.short("p")
.help("Print the resulting Cranelift IR")
}
fn add_debug_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("debug")
.short("d")
.help("Enable debug output on stderr/stdout")
}
fn add_just_decode_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("just-decode")
.short("t")
.help("Just decode into Cranelift IR")
}
fn add_check_translation_flag<'a>() -> clap::Arg<'a, 'a> {
Arg::with_name("check-translation")
.short("c")
.help("Just checks the correctness of Cranelift IR translated from WebAssembly")
}
/// Returns a vector of clap value options and changes these options into a vector of strings
fn get_vec(argument_vec: Option<clap::Values>) -> Vec<String> {
let mut ret_vec: Vec<String> = Vec::new();
if let Some(clap_vec) = argument_vec {
for val in clap_vec {
ret_vec.push(val.to_string());
}
}
ret_vec
}
fn add_wasm_or_compile<'a>(cmd: &str) -> clap::App<'a, 'a> {
let about_str = match cmd {
"wasm" => "Compiles Wasm binary/text into Cranelift IR and then into target language",
"compile" => "Compiles Cranelift IR into target language",
_ => panic!("Invalid command"),
};
SubCommand::with_name(cmd)
.about(about_str)
.arg(add_verbose_flag())
.arg(add_print_flag())
.arg(add_time_flag())
.arg(add_size_flag())
.arg(add_disasm_flag())
.arg(add_set_flag())
.arg(add_target_flag())
.arg(add_input_file_arg())
.arg(add_debug_flag())
.arg(add_just_decode_flag())
.arg(add_check_translation_flag())
}
fn handle_debug_flag(debug: bool) {
if debug {
pretty_env_logger::init();
} else {
file_per_thread_logger::initialize(LOG_FILENAME_PREFIX);
}
}
fn main() {
let app_cmds = App::new("Cranelift code generator utility")
.version(VERSION)
.subcommand(
SubCommand::with_name("test")
.about("Run Cranelift tests")
.arg(add_verbose_flag())
.arg(add_time_flag())
.arg(add_input_file_arg())
.arg(add_debug_flag()),
)
.subcommand(
SubCommand::with_name("run")
.about("Execute CLIF code and verify with test expressions")
.arg(add_verbose_flag())
.arg(add_input_file_arg())
.arg(add_debug_flag()),
)
.subcommand(
SubCommand::with_name("cat")
.about("Outputs .clif file")
.arg(add_input_file_arg())
.arg(add_debug_flag()),
)
.subcommand(
SubCommand::with_name("print-cfg")
.about("Prints out cfg in dot format")
.arg(add_input_file_arg())
.arg(add_debug_flag()),
)
.subcommand(add_wasm_or_compile("compile"))
.subcommand(
add_wasm_or_compile("wasm").arg(
Arg::with_name("value-ranges")
.long("value-ranges")
.help("Display values ranges and their locations"),
),
)
.subcommand(
SubCommand::with_name("pass")
.about("Run specified pass(s) on an input file.")
.arg(add_single_input_file_arg())
.arg(add_target_flag())
.arg(add_pass_arg())
.arg(add_debug_flag())
.arg(add_time_flag()),
)
.subcommand(
SubCommand::with_name("bugpoint")
.about("Reduce size of clif file causing panic during compilation.")
.arg(add_single_input_file_arg())
.arg(add_set_flag())
.arg(add_target_flag())
.arg(add_verbose_flag()),
);
let res_util = match app_cmds.get_matches().subcommand() {
("cat", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
cat::run(&get_vec(rest_cmd.values_of("file")))
}
("test", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
cranelift_filetests::run(
rest_cmd.is_present("verbose"),
rest_cmd.is_present("time-passes"),
&get_vec(rest_cmd.values_of("file")),
)
.map(|_time| ())
}
("run", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
run::run(
get_vec(rest_cmd.values_of("file")),
rest_cmd.is_present("verbose"),
)
.map(|_time| ())
}
("pass", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
let mut target_val: &str = "";
if let Some(clap_target) = rest_cmd.value_of("target") {
target_val = clap_target;
}
// Can be unwrapped because 'single-file' is required
cranelift_filetests::run_passes(
rest_cmd.is_present("verbose"),
rest_cmd.is_present("time-passes"),
&get_vec(rest_cmd.values_of("pass")),
target_val,
rest_cmd.value_of("single-file").unwrap(),
)
.map(|_time| ())
}
("print-cfg", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
print_cfg::run(&get_vec(rest_cmd.values_of("file")))
}
("compile", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
let mut target_val: &str = "";
if let Some(clap_target) = rest_cmd.value_of("target") {
target_val = clap_target;
}
compile::run(
get_vec(rest_cmd.values_of("file")),
rest_cmd.is_present("print"),
rest_cmd.is_present("disasm"),
rest_cmd.is_present("time-passes"),
&get_vec(rest_cmd.values_of("set")),
target_val,
)
}
("wasm", Some(rest_cmd)) => {
handle_debug_flag(rest_cmd.is_present("debug"));
#[cfg(feature = "wasm")]
let result = {
let mut target_val: &str = "";
if let Some(clap_target) = rest_cmd.value_of("target") {
target_val = clap_target;
}
wasm::run(
get_vec(rest_cmd.values_of("file")),
rest_cmd.is_present("verbose"),
rest_cmd.is_present("just-decode"),
rest_cmd.is_present("check-translation"),
rest_cmd.is_present("print"),
rest_cmd.is_present("disasm"),
&get_vec(rest_cmd.values_of("set")),
target_val,
rest_cmd.is_present("print-size"),
rest_cmd.is_present("time-passes"),
rest_cmd.is_present("value-ranges"),
)
};
#[cfg(not(feature = "wasm"))]
let result = Err("Error: clif-util was compiled without wasm support.".to_owned());
result
}
("bugpoint", Some(rest_cmd)) => {
let mut target_val: &str = "";
if let Some(clap_target) = rest_cmd.value_of("target") {
target_val = clap_target;
}
bugpoint::run(
rest_cmd.value_of("single-file").unwrap(),
&get_vec(rest_cmd.values_of("set")),
target_val,
rest_cmd.is_present("verbose"),
)
}
_ => Err("Invalid subcommand.".to_owned()),
};
if let Err(mut msg) = res_util {
if !msg.ends_with('\n') {
msg.push('\n');
}
io::stdout().flush().expect("flushing stdout");
io::stderr().write_all(msg.as_bytes()).unwrap();
process::exit(1);
}
}