* Changing from docopt to clap for the clif-util * Updates to cargo file. * Remove filecheck subcommand.
This commit is contained in:
committed by
Dan Gohman
parent
77eb38c41f
commit
0f93ef5cee
@@ -27,9 +27,8 @@ cranelift-faerie = { path = "lib/faerie", version = "0.19.0" }
|
|||||||
cranelift-simplejit = { path = "lib/simplejit", version = "0.19.0" }
|
cranelift-simplejit = { path = "lib/simplejit", version = "0.19.0" }
|
||||||
cranelift = { path = "lib/umbrella", version = "0.19.0" }
|
cranelift = { path = "lib/umbrella", version = "0.19.0" }
|
||||||
filecheck = "0.3.0"
|
filecheck = "0.3.0"
|
||||||
docopt = "1"
|
clap = "2.32.0"
|
||||||
serde = "1.0.8"
|
serde = "1.0.8"
|
||||||
serde_derive = "1.0.8"
|
|
||||||
term = "0.5.1"
|
term = "0.5.1"
|
||||||
capstone = { version = "0.4", optional = true }
|
capstone = { version = "0.4", optional = true }
|
||||||
wabt = { version = "0.4", optional = true }
|
wabt = { version = "0.4", optional = true }
|
||||||
|
|||||||
@@ -8,23 +8,20 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
extern crate file_per_thread_logger;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cfg_if;
|
extern crate cfg_if;
|
||||||
extern crate cranelift_codegen;
|
|
||||||
extern crate cranelift_filetests;
|
|
||||||
extern crate cranelift_reader;
|
|
||||||
extern crate docopt;
|
|
||||||
extern crate file_per_thread_logger;
|
|
||||||
extern crate filecheck;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
#[cfg(feature = "disas")]
|
#[cfg(feature = "disas")]
|
||||||
extern crate capstone;
|
extern crate capstone;
|
||||||
|
extern crate clap;
|
||||||
|
extern crate cranelift_codegen;
|
||||||
|
extern crate cranelift_entity;
|
||||||
|
extern crate cranelift_filetests;
|
||||||
|
extern crate cranelift_reader;
|
||||||
extern crate pretty_env_logger;
|
extern crate pretty_env_logger;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "wasm")] {
|
if #[cfg(feature = "wasm")] {
|
||||||
extern crate cranelift_entity;
|
|
||||||
extern crate cranelift_wasm;
|
extern crate cranelift_wasm;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate wabt;
|
extern crate wabt;
|
||||||
@@ -33,137 +30,200 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
extern crate target_lexicon;
|
extern crate target_lexicon;
|
||||||
|
|
||||||
|
use clap::{App, Arg, SubCommand};
|
||||||
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
|
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
|
||||||
use cranelift_codegen::{timing, VERSION};
|
use cranelift_codegen::VERSION;
|
||||||
use docopt::Docopt;
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use std::option::Option;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
mod cat;
|
mod cat;
|
||||||
mod compile;
|
mod compile;
|
||||||
mod print_cfg;
|
mod print_cfg;
|
||||||
mod rsfilecheck;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
const USAGE: &str = "
|
|
||||||
Cranelift code generator utility
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
clif-util test [-vTd] <file>...
|
|
||||||
clif-util cat [-d] <file>...
|
|
||||||
clif-util filecheck [-vd] <file>
|
|
||||||
clif-util print-cfg [-d] <file>...
|
|
||||||
clif-util compile [-vpTd] [--set <set>]... [--target <triple>] <file>...
|
|
||||||
clif-util wasm [-ctvpTsd] [--set <set>]... [--target <triple>] <file>...
|
|
||||||
clif-util --help | --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-v, --verbose be more verbose
|
|
||||||
-d, --debug enable debug output on stderr/stdout
|
|
||||||
-T, --time-passes
|
|
||||||
print pass timing report
|
|
||||||
-t, --just-decode
|
|
||||||
just decode WebAssembly to Cranelift IR
|
|
||||||
-s, --print-size
|
|
||||||
prints generated code size
|
|
||||||
-c, --check-translation
|
|
||||||
just checks the correctness of Cranelift IR translated from WebAssembly
|
|
||||||
-p, --print print the resulting Cranelift IR
|
|
||||||
-h, --help print this help message
|
|
||||||
--set=<set> configure Cranelift settings
|
|
||||||
--target=<triple>
|
|
||||||
specify the Cranelift target
|
|
||||||
--version print the Cranelift version
|
|
||||||
|
|
||||||
";
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct Args {
|
|
||||||
cmd_test: bool,
|
|
||||||
cmd_cat: bool,
|
|
||||||
cmd_filecheck: bool,
|
|
||||||
cmd_print_cfg: bool,
|
|
||||||
cmd_compile: bool,
|
|
||||||
cmd_wasm: bool,
|
|
||||||
arg_file: Vec<String>,
|
|
||||||
flag_just_decode: bool,
|
|
||||||
flag_check_translation: bool,
|
|
||||||
flag_print: bool,
|
|
||||||
flag_verbose: bool,
|
|
||||||
flag_set: Vec<String>,
|
|
||||||
flag_target: String,
|
|
||||||
flag_time_passes: bool,
|
|
||||||
flag_print_size: bool,
|
|
||||||
flag_debug: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A command either succeeds or fails with an error message.
|
/// A command either succeeds or fails with an error message.
|
||||||
pub type CommandResult = Result<(), String>;
|
pub type CommandResult = Result<(), String>;
|
||||||
|
|
||||||
/// Parse the command line arguments and run the requested command.
|
fn add_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
fn clif_util() -> CommandResult {
|
Arg::with_name("file")
|
||||||
// Parse command line arguments.
|
.required(true)
|
||||||
let args: Args = Docopt::new(USAGE)
|
.multiple(true)
|
||||||
.and_then(|d| {
|
.value_name("file")
|
||||||
d.help(true)
|
.help("Specify file(s) to be used for test")
|
||||||
.version(Some(format!("Cranelift {}", VERSION)))
|
}
|
||||||
.deserialize()
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|e| e.exit());
|
|
||||||
|
|
||||||
if args.flag_debug {
|
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_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")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a vector of clap value options and changes these options into a vector of strings
|
||||||
|
fn get_vec<'a>(argument_vec: Option<clap::Values<'a>>) -> 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 Cranelift IR 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_set_flag())
|
||||||
|
.arg(add_target_flag())
|
||||||
|
.arg(add_input_file_arg())
|
||||||
|
.arg(add_debug_flag())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_debug_flag(debug: bool) {
|
||||||
|
if debug {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
} else {
|
} else {
|
||||||
file_per_thread_logger::initialize(LOG_FILENAME_PREFIX);
|
file_per_thread_logger::initialize(LOG_FILENAME_PREFIX);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the sub-command to execute.
|
fn main() {
|
||||||
let result = if args.cmd_test {
|
let app_cmds = App::new("Cranelift code generator utility")
|
||||||
cranelift_filetests::run(args.flag_verbose, &args.arg_file).map(|_time| ())
|
.version(VERSION)
|
||||||
} else if args.cmd_cat {
|
.subcommand(
|
||||||
cat::run(&args.arg_file)
|
SubCommand::with_name("test")
|
||||||
} else if args.cmd_filecheck {
|
.about("Run Cranelift tests")
|
||||||
rsfilecheck::run(&args.arg_file, args.flag_verbose)
|
.arg(add_verbose_flag())
|
||||||
} else if args.cmd_print_cfg {
|
.arg(add_time_flag())
|
||||||
print_cfg::run(&args.arg_file)
|
.arg(add_input_file_arg())
|
||||||
} else if args.cmd_compile {
|
.arg(add_debug_flag()),
|
||||||
compile::run(
|
|
||||||
args.arg_file,
|
|
||||||
args.flag_print,
|
|
||||||
&args.flag_set,
|
|
||||||
&args.flag_target,
|
|
||||||
)
|
)
|
||||||
} else if args.cmd_wasm {
|
.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")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("just-decode")
|
||||||
|
.short("t")
|
||||||
|
.help("Just decode WebAssembly to Cranelift IR"),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("check-translation").short("c").help(
|
||||||
|
"Just checks the correctness of Cranelift IR translated from WebAssembly",
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.subcommand(add_wasm_or_compile("wasm"));
|
||||||
|
|
||||||
|
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("time-passes"),
|
||||||
|
&get_vec(rest_cmd.values_of("file")),
|
||||||
|
).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"),
|
||||||
|
&get_vec(rest_cmd.values_of("set")),
|
||||||
|
target_val,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
("wasm", 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;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
let result = wasm::run(
|
let result = wasm::run(
|
||||||
args.arg_file,
|
get_vec(rest_cmd.values_of("file")),
|
||||||
args.flag_verbose,
|
rest_cmd.is_present("verbose"),
|
||||||
args.flag_just_decode,
|
rest_cmd.is_present("just-decode"),
|
||||||
args.flag_check_translation,
|
rest_cmd.is_present("check-translation"),
|
||||||
args.flag_print,
|
rest_cmd.is_present("print"),
|
||||||
&args.flag_set,
|
&get_vec(rest_cmd.values_of("set")),
|
||||||
&args.flag_target,
|
target_val,
|
||||||
args.flag_print_size,
|
rest_cmd.is_present("print-size"),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
let result = Err("Error: clif-util was compiled without wasm support.".to_owned());
|
let result = Err("Error: clif-util was compiled without wasm support.".to_owned());
|
||||||
|
|
||||||
result
|
result
|
||||||
} else {
|
}
|
||||||
// Debugging / shouldn't happen with proper command line handling above.
|
_ => Err(format!("Invalid subcommand.")),
|
||||||
Err(format!("Unhandled args: {:?}", args))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if args.flag_time_passes {
|
if let Err(mut msg) = res_util {
|
||||||
print!("{}", timing::take_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
if let Err(mut msg) = clif_util() {
|
|
||||||
if !msg.ends_with('\n') {
|
if !msg.ends_with('\n') {
|
||||||
msg.push('\n');
|
msg.push('\n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
//! The `filecheck` sub-command.
|
|
||||||
//!
|
|
||||||
//! This file is named to avoid a name collision with the filecheck crate.
|
|
||||||
|
|
||||||
use filecheck::{Checker, CheckerBuilder, NO_VARIABLES};
|
|
||||||
use std::io::{self, Read};
|
|
||||||
use utils::read_to_string;
|
|
||||||
use CommandResult;
|
|
||||||
|
|
||||||
pub fn run(files: &[String], verbose: bool) -> CommandResult {
|
|
||||||
if files.is_empty() {
|
|
||||||
return Err("No check files".to_string());
|
|
||||||
}
|
|
||||||
let checker = read_checkfile(&files[0])?;
|
|
||||||
if checker.is_empty() {
|
|
||||||
return Err(format!("{}: no filecheck directives found", files[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the directives under --verbose.
|
|
||||||
if verbose {
|
|
||||||
println!("{}", checker);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
io::stdin()
|
|
||||||
.read_to_string(&mut buffer)
|
|
||||||
.map_err(|e| format!("stdin: {}", e))?;
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
let (success, explain) = checker
|
|
||||||
.explain(&buffer, NO_VARIABLES)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
print!("{}", explain);
|
|
||||||
if success {
|
|
||||||
println!("OK");
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err("Check failed".to_string())
|
|
||||||
}
|
|
||||||
} else if checker
|
|
||||||
.check(&buffer, NO_VARIABLES)
|
|
||||||
.map_err(|e| e.to_string())?
|
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
let (_, explain) = checker
|
|
||||||
.explain(&buffer, NO_VARIABLES)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
print!("{}", explain);
|
|
||||||
Err("Check failed".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_checkfile(filename: &str) -> Result<Checker, String> {
|
|
||||||
let buffer = read_to_string(&filename).map_err(|e| format!("{}: {}", filename, e))?;
|
|
||||||
let mut builder = CheckerBuilder::new();
|
|
||||||
builder
|
|
||||||
.text(&buffer)
|
|
||||||
.map_err(|e| format!("{}: {}", filename, e))?;
|
|
||||||
Ok(builder.finish())
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user