clif-util: Switch to using structopt for CLI arguments
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -548,7 +548,6 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"capstone",
|
"capstone",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"clap",
|
|
||||||
"cranelift",
|
"cranelift",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
@@ -570,6 +569,7 @@ dependencies = [
|
|||||||
"peepmatic-souper",
|
"peepmatic-souper",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"structopt",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"term",
|
"term",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -1972,9 +1972,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structopt"
|
name = "structopt"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c"
|
checksum = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -1983,9 +1983,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structopt-derive"
|
name = "structopt-derive"
|
||||||
version = "0.4.8"
|
version = "0.4.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118"
|
checksum = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ cranelift-simplejit = { path = "simplejit", version = "0.66.0" }
|
|||||||
cranelift-preopt = { path = "preopt", version = "0.66.0" }
|
cranelift-preopt = { path = "preopt", version = "0.66.0" }
|
||||||
cranelift = { path = "umbrella", version = "0.66.0" }
|
cranelift = { path = "umbrella", version = "0.66.0" }
|
||||||
filecheck = "0.5.0"
|
filecheck = "0.5.0"
|
||||||
clap = "2.32.0"
|
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
term = "0.6.1"
|
term = "0.6.1"
|
||||||
capstone = { version = "0.6.0", optional = true }
|
capstone = { version = "0.6.0", optional = true }
|
||||||
@@ -44,6 +43,7 @@ indicatif = "0.13.0"
|
|||||||
thiserror = "1.0.15"
|
thiserror = "1.0.15"
|
||||||
walkdir = "2.2"
|
walkdir = "2.2"
|
||||||
anyhow = "1.0.32"
|
anyhow = "1.0.32"
|
||||||
|
structopt = "0.3.17"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["disas", "wasm", "cranelift-codegen/all-arch", "peepmatic-souper", "souper-harvest"]
|
default = ["disas", "wasm", "cranelift-codegen/all-arch", "peepmatic-souper", "souper-harvest"]
|
||||||
|
|||||||
@@ -16,17 +16,35 @@ use cranelift_entity::PrimaryMap;
|
|||||||
use cranelift_reader::{parse_test, ParseOptions};
|
use cranelift_reader::{parse_test, ParseOptions};
|
||||||
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub fn run(filename: &str, flag_set: &[String], flag_isa: &str, verbose: bool) -> Result<()> {
|
/// Reduce size of clif file causing panic during compilation.
|
||||||
let parsed = parse_sets_and_triple(flag_set, flag_isa)?;
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
file: PathBuf,
|
||||||
|
|
||||||
|
/// Configure Cranelift settings
|
||||||
|
#[structopt(long("set"))]
|
||||||
|
settings: Vec<String>,
|
||||||
|
|
||||||
|
/// Specify the target architecture.
|
||||||
|
target: String,
|
||||||
|
|
||||||
|
/// Be more verbose
|
||||||
|
#[structopt(short = "v", long = "verbose")]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
let parsed = parse_sets_and_triple(&options.settings, &options.target)?;
|
||||||
let fisa = parsed.as_fisa();
|
let fisa = parsed.as_fisa();
|
||||||
|
|
||||||
let path = Path::new(&filename).to_path_buf();
|
let buffer = read_to_string(&options.file)?;
|
||||||
|
|
||||||
let buffer = read_to_string(&path)?;
|
|
||||||
let test_file = parse_test(&buffer, ParseOptions::default())
|
let test_file = parse_test(&buffer, ParseOptions::default())
|
||||||
.with_context(|| format!("failed to parse {}", filename))?;
|
.with_context(|| format!("failed to parse {}", options.file.display()))?;
|
||||||
|
|
||||||
// If we have an isa from the command-line, use that. Otherwise if the
|
// If we have an isa from the command-line, use that. Otherwise if the
|
||||||
// file contains a unique isa, use that.
|
// file contains a unique isa, use that.
|
||||||
@@ -43,7 +61,7 @@ pub fn run(filename: &str, flag_set: &[String], flag_isa: &str, verbose: bool) -
|
|||||||
for (func, _) in test_file.functions {
|
for (func, _) in test_file.functions {
|
||||||
let (orig_block_count, orig_inst_count) = (block_count(&func), inst_count(&func));
|
let (orig_block_count, orig_inst_count) = (block_count(&func), inst_count(&func));
|
||||||
|
|
||||||
match reduce(isa, func, verbose) {
|
match reduce(isa, func, options.verbose) {
|
||||||
Ok((func, crash_msg)) => {
|
Ok((func, crash_msg)) => {
|
||||||
println!("Crash message: {}", crash_msg);
|
println!("Crash message: {}", crash_msg);
|
||||||
println!("\n{}", func);
|
println!("\n{}", func);
|
||||||
|
|||||||
@@ -6,9 +6,24 @@
|
|||||||
use crate::utils::read_to_string;
|
use crate::utils::read_to_string;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use cranelift_reader::parse_functions;
|
use cranelift_reader::parse_functions;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub fn run(files: &[String]) -> Result<()> {
|
/// Outputs .clif file
|
||||||
for (i, f) in files.iter().enumerate() {
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify input file(s) to be used. Use '-' for stdin.
|
||||||
|
#[structopt(required(true), parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
for (i, f) in options.files.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@@ -17,10 +32,10 @@ pub fn run(files: &[String]) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cat_one(filename: &str) -> Result<()> {
|
fn cat_one(path: &Path) -> Result<()> {
|
||||||
let buffer = read_to_string(&filename)?;
|
let buffer = read_to_string(path)?;
|
||||||
let items =
|
let items =
|
||||||
parse_functions(&buffer).with_context(|| format!("failed to parse {}", filename))?;
|
parse_functions(&buffer).with_context(|| format!("failed to parse {}", path.display()))?;
|
||||||
|
|
||||||
for (idx, func) in items.into_iter().enumerate() {
|
for (idx, func) in items.into_iter().enumerate() {
|
||||||
if idx != 0 {
|
if idx != 0 {
|
||||||
|
|||||||
490
cranelift/src/clif-util.rs
Executable file → Normal file
490
cranelift/src/clif-util.rs
Executable file → Normal file
@@ -13,10 +13,9 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use clap::{arg_enum, App, Arg, SubCommand};
|
|
||||||
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
|
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
|
||||||
use cranelift_codegen::VERSION;
|
use std::{option::Option, path::PathBuf};
|
||||||
use std::option::Option;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
mod bugpoint;
|
mod bugpoint;
|
||||||
mod cat;
|
mod cat;
|
||||||
@@ -25,9 +24,10 @@ mod disasm;
|
|||||||
mod interpret;
|
mod interpret;
|
||||||
mod print_cfg;
|
mod print_cfg;
|
||||||
mod run;
|
mod run;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
#[cfg(feature = "souper-harvest")]
|
#[cfg(feature = "souper-harvest")]
|
||||||
mod souper_harvest;
|
mod souper_harvest;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
#[cfg(feature = "peepmatic-souper")]
|
#[cfg(feature = "peepmatic-souper")]
|
||||||
mod souper_to_peepmatic;
|
mod souper_to_peepmatic;
|
||||||
@@ -35,157 +35,6 @@ mod souper_to_peepmatic;
|
|||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
mod wasm;
|
mod wasm;
|
||||||
|
|
||||||
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_output_arg<'a>() -> clap::Arg<'a, 'a> {
|
|
||||||
Arg::with_name("output")
|
|
||||||
.required(true)
|
|
||||||
.default_value("-")
|
|
||||||
.value_name("output")
|
|
||||||
.short("o")
|
|
||||||
.help("Specify output file to be used. Use '-' for stdout.")
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_enum! {
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub enum UseTerminalColor {
|
|
||||||
Auto,
|
|
||||||
Never,
|
|
||||||
Always
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_color<'a>() -> clap::Arg<'a, 'a> {
|
|
||||||
Arg::with_name("color")
|
|
||||||
.long("color")
|
|
||||||
.possible_values(&UseTerminalColor::variants())
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(false)
|
|
||||||
.default_value("auto")
|
|
||||||
.case_insensitive(true)
|
|
||||||
.help("Use colors in output")
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_value_ranges<'a>() -> clap::Arg<'a, 'a> {
|
|
||||||
Arg::with_name("value-ranges")
|
|
||||||
.long("value-ranges")
|
|
||||||
.help("Display values ranges and their locations")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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_disasm_flag())
|
|
||||||
.arg(add_set_flag())
|
|
||||||
.arg(add_target_flag())
|
|
||||||
.arg(add_input_file_arg())
|
|
||||||
.arg(add_debug_flag())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_debug_flag(debug: bool) {
|
fn handle_debug_flag(debug: bool) {
|
||||||
if debug {
|
if debug {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
@@ -194,229 +43,138 @@ fn handle_debug_flag(debug: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
/// Cranelift code generator utility.
|
||||||
let app_cmds = App::new("Cranelift code generator utility")
|
#[derive(StructOpt)]
|
||||||
.version(VERSION)
|
enum Commands {
|
||||||
.subcommand(
|
Test(TestOptions),
|
||||||
SubCommand::with_name("test")
|
Run(run::Options),
|
||||||
.about("Run Cranelift tests")
|
Interpret(interpret::Options),
|
||||||
.arg(add_verbose_flag())
|
Cat(cat::Options),
|
||||||
.arg(add_time_flag())
|
PrintCfg(print_cfg::Options),
|
||||||
.arg(add_input_file_arg())
|
Compile(compile::Options),
|
||||||
.arg(add_debug_flag()),
|
Pass(PassOptions),
|
||||||
)
|
Bugpoint(bugpoint::Options),
|
||||||
.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("interpret")
|
|
||||||
.about("Interpret CLIF code")
|
|
||||||
.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(add_size_flag())
|
|
||||||
.arg(add_just_decode_flag())
|
|
||||||
.arg(add_check_translation_flag())
|
|
||||||
.arg(add_value_ranges())
|
|
||||||
.arg(add_color()),
|
|
||||||
)
|
|
||||||
.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()),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("souper-to-peepmatic")
|
|
||||||
.about("Convert Souper optimizations into Peepmatic DSL.")
|
|
||||||
.arg(add_single_input_file_arg())
|
|
||||||
.arg(add_output_arg()),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("souper-harvest")
|
|
||||||
.arg(add_single_input_file_arg())
|
|
||||||
.arg(add_output_arg())
|
|
||||||
.arg(add_target_flag())
|
|
||||||
.arg(add_set_flag()),
|
|
||||||
);
|
|
||||||
|
|
||||||
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_err(|s| anyhow::anyhow!("{}", s))?;
|
|
||||||
}
|
|
||||||
("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"),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
("interpret", Some(rest_cmd)) => {
|
|
||||||
handle_debug_flag(rest_cmd.is_present("debug"));
|
|
||||||
interpret::run(
|
|
||||||
get_vec(rest_cmd.values_of("file")),
|
|
||||||
rest_cmd.is_present("verbose"),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
("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_err(|s| anyhow::anyhow!("{}", s))?;
|
|
||||||
}
|
|
||||||
("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")]
|
#[cfg(feature = "wasm")]
|
||||||
{
|
Wasm(wasm::Options),
|
||||||
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.value_of("color").unwrap().parse().unwrap(),
|
|
||||||
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"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
{
|
Wasm(CompiledWithoutSupportOptions),
|
||||||
anyhow::bail!("Error: clif-util was compiled without wasm support.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("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"),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
("souper-to-peepmatic", Some(rest_cmd)) => {
|
|
||||||
#[cfg(feature = "peepmatic-souper")]
|
#[cfg(feature = "peepmatic-souper")]
|
||||||
{
|
SouperToPeepmatic(souper_to_peepmatic::Options),
|
||||||
use std::path::Path;
|
|
||||||
souper_to_peepmatic::run(
|
|
||||||
Path::new(rest_cmd.value_of("single-file").unwrap()),
|
|
||||||
Path::new(rest_cmd.value_of("output").unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "peepmatic-souper"))]
|
#[cfg(not(feature = "peepmatic-souper"))]
|
||||||
{
|
SouperToPeepmatic(CompiledWithoutSupportOptions),
|
||||||
anyhow::bail!(
|
|
||||||
"Error: clif-util was compiled without suport for the `souper-to-peepmatic` \
|
|
||||||
subcommand"
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("souper-harvest", Some(rest_cmd)) => {
|
|
||||||
#[cfg(feature = "souper-harvest")]
|
#[cfg(feature = "souper-harvest")]
|
||||||
{
|
SouperHarvest(souper_harvest::Options),
|
||||||
souper_harvest::run(
|
#[cfg(not(feature = "souper-harvest"))]
|
||||||
rest_cmd.value_of("target").unwrap_or_default(),
|
SouperHarvest(CompiledWithoutSupportOptions),
|
||||||
rest_cmd.value_of("single-file").unwrap(),
|
|
||||||
rest_cmd.value_of("output").unwrap(),
|
|
||||||
&get_vec(rest_cmd.values_of("set")),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run Cranelift tests
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
struct TestOptions {
|
||||||
|
/// Be more verbose
|
||||||
|
#[structopt(short = "v", long = "verbose")]
|
||||||
|
verbose: bool,
|
||||||
|
|
||||||
|
/// Print pass timing report for test
|
||||||
|
#[structopt(short = "T")]
|
||||||
|
time_passes: bool,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(required(true), parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run specified pass(es) on an input file.
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
struct PassOptions {
|
||||||
|
/// Be more verbose
|
||||||
|
#[structopt(short = "v", long = "verbose")]
|
||||||
|
verbose: bool,
|
||||||
|
|
||||||
|
/// Print pass timing report for test
|
||||||
|
#[structopt(short = "T")]
|
||||||
|
time_passes: bool,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
file: PathBuf,
|
||||||
|
|
||||||
|
/// Specify the target architecture.
|
||||||
|
target: String,
|
||||||
|
|
||||||
|
/// Specify pass(es) to be run on the input file
|
||||||
|
#[structopt(required(true))]
|
||||||
|
passes: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (Compiled without support for this subcommand)
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
struct CompiledWithoutSupportOptions {}
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
match Commands::from_args() {
|
||||||
|
Commands::Cat(c) => cat::run(&c)?,
|
||||||
|
Commands::Run(r) => run::run(&r)?,
|
||||||
|
Commands::Interpret(i) => interpret::run(&i)?,
|
||||||
|
Commands::PrintCfg(p) => print_cfg::run(&p)?,
|
||||||
|
Commands::Compile(c) => compile::run(&c)?,
|
||||||
|
Commands::Bugpoint(b) => bugpoint::run(&b)?,
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
Commands::Wasm(w) => wasm::run(&w)?,
|
||||||
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
Commands::Wasm(_) => anyhow::bail!("Error: clif-util was compiled without wasm support."),
|
||||||
|
|
||||||
|
#[cfg(feature = "peepmatic-souper")]
|
||||||
|
Commands::SouperToPeepmatic(s) => souper_to_peepmatic::run(&s)?,
|
||||||
|
#[cfg(not(feature = "peepmatic-souper"))]
|
||||||
|
Commands::SouperToPeepmatic(_) => anyhow::bail!(
|
||||||
|
"Error: clif-util was compiled without support for the `souper-to-peepmatic` \
|
||||||
|
subcommand",
|
||||||
|
),
|
||||||
|
|
||||||
|
#[cfg(feature = "souper-harvest")]
|
||||||
|
Commands::SouperHarvest(s) => souper_harvest::run(&s)?,
|
||||||
#[cfg(not(feature = "souper-harvest"))]
|
#[cfg(not(feature = "souper-harvest"))]
|
||||||
{
|
Commands::SouperHarvest(_) => anyhow::bail!(
|
||||||
anyhow::bail!("clif-util was compiled without `souper-harvest` support");
|
"Error: clif-util was compiled without support for the `souper-harvest` \
|
||||||
|
subcommand",
|
||||||
|
),
|
||||||
|
|
||||||
|
Commands::Test(t) => {
|
||||||
|
handle_debug_flag(t.debug);
|
||||||
|
cranelift_filetests::run(
|
||||||
|
t.verbose,
|
||||||
|
t.time_passes,
|
||||||
|
&t.files
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.display().to_string())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.map_err(|s| anyhow::anyhow!("{}", s))?;
|
||||||
}
|
}
|
||||||
|
Commands::Pass(p) => {
|
||||||
|
handle_debug_flag(p.debug);
|
||||||
|
cranelift_filetests::run_passes(
|
||||||
|
p.verbose,
|
||||||
|
p.time_passes,
|
||||||
|
&p.passes,
|
||||||
|
&p.target,
|
||||||
|
&p.file.display().to_string(),
|
||||||
|
)
|
||||||
|
.map_err(|s| anyhow::anyhow!("{}", s))?;
|
||||||
}
|
}
|
||||||
_ => anyhow::bail!("Invalid subcommand.".to_owned()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -10,40 +10,51 @@ use cranelift_codegen::Context;
|
|||||||
use cranelift_reader::{parse_test, ParseOptions};
|
use cranelift_reader::{parse_test, ParseOptions};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub fn run(
|
/// Compiles Cranelift IR into target language
|
||||||
files: Vec<String>,
|
#[derive(StructOpt)]
|
||||||
flag_print: bool,
|
pub struct Options {
|
||||||
flag_disasm: bool,
|
/// Print the resulting Cranelift IR
|
||||||
flag_report_times: bool,
|
#[structopt(short("p"))]
|
||||||
flag_set: &[String],
|
print: bool,
|
||||||
flag_isa: &str,
|
|
||||||
) -> Result<()> {
|
|
||||||
let parsed = parse_sets_and_triple(flag_set, flag_isa)?;
|
|
||||||
|
|
||||||
for filename in files {
|
/// Print pass timing report
|
||||||
let path = Path::new(&filename);
|
#[structopt(short("T"))]
|
||||||
|
report_times: bool,
|
||||||
|
|
||||||
|
/// Print machine code disassembly
|
||||||
|
#[structopt(short("D"), long("disasm"))]
|
||||||
|
disasm: bool,
|
||||||
|
|
||||||
|
/// Configure Cranelift settings
|
||||||
|
#[structopt(long("set"))]
|
||||||
|
settings: Vec<String>,
|
||||||
|
|
||||||
|
/// Specify the Cranelift target
|
||||||
|
#[structopt(long("target"))]
|
||||||
|
target: String,
|
||||||
|
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
let parsed = parse_sets_and_triple(&options.settings, &options.target)?;
|
||||||
|
for path in &options.files {
|
||||||
let name = String::from(path.as_os_str().to_string_lossy());
|
let name = String::from(path.as_os_str().to_string_lossy());
|
||||||
handle_module(
|
handle_module(options, path, &name, parsed.as_fisa())?;
|
||||||
flag_print,
|
|
||||||
flag_disasm,
|
|
||||||
flag_report_times,
|
|
||||||
&path.to_path_buf(),
|
|
||||||
&name,
|
|
||||||
parsed.as_fisa(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(
|
fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) -> Result<()> {
|
||||||
flag_print: bool,
|
|
||||||
flag_disasm: bool,
|
|
||||||
flag_report_times: bool,
|
|
||||||
path: &PathBuf,
|
|
||||||
name: &str,
|
|
||||||
fisa: FlagsOrIsa,
|
|
||||||
) -> Result<()> {
|
|
||||||
let buffer = read_to_string(&path)?;
|
let buffer = read_to_string(&path)?;
|
||||||
let test_file = parse_test(&buffer, ParseOptions::default())
|
let test_file = parse_test(&buffer, ParseOptions::default())
|
||||||
.with_context(|| format!("failed to parse {}", name))?;
|
.with_context(|| format!("failed to parse {}", name))?;
|
||||||
@@ -57,9 +68,9 @@ fn handle_module(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (func, _) in test_file.functions {
|
for (func, _) in test_file.functions {
|
||||||
let mut relocs = PrintRelocs::new(flag_print);
|
let mut relocs = PrintRelocs::new(options.print);
|
||||||
let mut traps = PrintTraps::new(flag_print);
|
let mut traps = PrintTraps::new(options.print);
|
||||||
let mut stack_maps = PrintStackMaps::new(flag_print);
|
let mut stack_maps = PrintStackMaps::new(options.print);
|
||||||
|
|
||||||
if let Some(isa) = isa {
|
if let Some(isa) = isa {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
@@ -73,11 +84,11 @@ fn handle_module(
|
|||||||
anyhow::anyhow!("{}", pretty_error(&context.func, Some(isa), err))
|
anyhow::anyhow!("{}", pretty_error(&context.func, Some(isa), err))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if flag_print {
|
if options.print {
|
||||||
println!("{}", context.func.display(isa));
|
println!("{}", context.func.display(isa));
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_disasm {
|
if options.disasm {
|
||||||
print_all(
|
print_all(
|
||||||
isa,
|
isa,
|
||||||
&mem,
|
&mem,
|
||||||
@@ -91,7 +102,7 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_report_times {
|
if options.report_times {
|
||||||
print!("{}", timing::take_current());
|
print!("{}", timing::take_current());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,23 +7,42 @@ use cranelift_reader::{parse_run_command, parse_test, ParseError, ParseOptions};
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
|
use structopt::StructOpt;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Interpret clif code
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(required(true), parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
|
/// Be more verbose
|
||||||
|
#[structopt(short = "v", long = "verbose")]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Run files through the Cranelift interpreter, interpreting any functions with annotations.
|
/// Run files through the Cranelift interpreter, interpreting any functions with annotations.
|
||||||
pub fn run(files: Vec<String>, flag_print: bool) -> anyhow::Result<()> {
|
pub fn run(options: &Options) -> anyhow::Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut errors = 0;
|
let mut errors = 0;
|
||||||
for file in iterate_files(files) {
|
for file in iterate_files(&options.files) {
|
||||||
total += 1;
|
total += 1;
|
||||||
let runner = FileInterpreter::from_path(file)?;
|
let runner = FileInterpreter::from_path(file)?;
|
||||||
match runner.run() {
|
match runner.run() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
println!("{}", runner.path());
|
println!("{}", runner.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
println!("{}: {}", runner.path(), e.to_string());
|
println!("{}: {}", runner.path(), e.to_string());
|
||||||
}
|
}
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@@ -31,7 +50,7 @@ pub fn run(files: Vec<String>, flag_print: bool) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
match total {
|
match total {
|
||||||
0 => println!("0 files"),
|
0 => println!("0 files"),
|
||||||
1 => println!("1 file"),
|
1 => println!("1 file"),
|
||||||
@@ -158,6 +177,11 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn filetests() {
|
fn filetests() {
|
||||||
run(vec!["../filetests/filetests/interpreter".to_string()], true).unwrap()
|
run(&Options {
|
||||||
|
files: vec![PathBuf::from("../filetests/filetests/interpreter")],
|
||||||
|
debug: true,
|
||||||
|
verbose: true,
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,24 @@ use crate::utils::read_to_string;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use cranelift_codegen::cfg_printer::CFGPrinter;
|
use cranelift_codegen::cfg_printer::CFGPrinter;
|
||||||
use cranelift_reader::parse_functions;
|
use cranelift_reader::parse_functions;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub fn run(files: &[String]) -> Result<()> {
|
/// Prints out cfg in GraphViz Dot format
|
||||||
for (i, f) in files.iter().enumerate() {
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(required(true), parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
for (i, f) in options.files.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@@ -18,8 +33,8 @@ pub fn run(files: &[String]) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_cfg(filename: &str) -> Result<()> {
|
fn print_cfg(path: &Path) -> Result<()> {
|
||||||
let buffer = read_to_string(filename)?;
|
let buffer = read_to_string(path)?;
|
||||||
let items = parse_functions(&buffer)?;
|
let items = parse_functions(&buffer)?;
|
||||||
|
|
||||||
for (idx, func) in items.into_iter().enumerate() {
|
for (idx, func) in items.into_iter().enumerate() {
|
||||||
|
|||||||
@@ -6,32 +6,55 @@ use cranelift_codegen::isa::{CallConv, TargetIsa};
|
|||||||
use cranelift_filetests::SingleFunctionCompiler;
|
use cranelift_filetests::SingleFunctionCompiler;
|
||||||
use cranelift_native::builder as host_isa_builder;
|
use cranelift_native::builder as host_isa_builder;
|
||||||
use cranelift_reader::{parse_run_command, parse_test, Details, IsaSpec, ParseOptions};
|
use cranelift_reader::{parse_run_command, parse_test, Details, IsaSpec, ParseOptions};
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
pub fn run(files: Vec<String>, flag_print: bool) -> Result<()> {
|
/// Execute clif code and verify with test expressions
|
||||||
let stdin_exist = files.iter().find(|file| *file == "-").is_some();
|
#[derive(StructOpt)]
|
||||||
let filtered_files = files
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(required(true), parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
|
/// Be more verbose
|
||||||
|
#[structopt(short = "v", long = "verbose")]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
let stdin_exist = options
|
||||||
|
.files
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|file| *file != "-")
|
.find(|file| *file == Path::new("-"))
|
||||||
.map(|file| file.to_string())
|
.is_some();
|
||||||
.collect::<Vec<String>>();
|
let filtered_files = options
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter(|file| *file != Path::new("-"))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut errors = 0;
|
let mut errors = 0;
|
||||||
let mut special_files: Vec<PathBuf> = vec![];
|
let mut special_files: Vec<PathBuf> = vec![];
|
||||||
if stdin_exist {
|
if stdin_exist {
|
||||||
special_files.push("-".into());
|
special_files.push("-".into());
|
||||||
}
|
}
|
||||||
for file in iterate_files(filtered_files).chain(special_files) {
|
for file in iterate_files(&filtered_files).chain(special_files) {
|
||||||
total += 1;
|
total += 1;
|
||||||
match run_single_file(&file) {
|
match run_single_file(&file) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
println!("{}", file.to_string_lossy());
|
println!("{}", file.to_string_lossy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
println!("{}: {}", file.to_string_lossy(), e);
|
println!("{}: {}", file.to_string_lossy(), e);
|
||||||
}
|
}
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@@ -39,7 +62,7 @@ pub fn run(files: Vec<String>, flag_print: bool) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_print {
|
if options.verbose {
|
||||||
match total {
|
match total {
|
||||||
0 => println!("0 files"),
|
0 => println!("0 files"),
|
||||||
1 => println!("1 file"),
|
1 => println!("1 file"),
|
||||||
|
|||||||
@@ -3,30 +3,57 @@ use anyhow::{Context as _, Result};
|
|||||||
use cranelift_codegen::Context;
|
use cranelift_codegen::Context;
|
||||||
use cranelift_wasm::{DummyEnvironment, ReturnMode};
|
use cranelift_wasm::{DummyEnvironment, ReturnMode};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
static WASM_MAGIC: &[u8] = &[0x00, 0x61, 0x73, 0x6D];
|
static WASM_MAGIC: &[u8] = &[0x00, 0x61, 0x73, 0x6D];
|
||||||
|
|
||||||
pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Result<()> {
|
/// Harvest candidates for superoptimization from a Wasm or Clif file.
|
||||||
let parsed = parse_sets_and_triple(flag_set, target)?;
|
///
|
||||||
|
/// Candidates are emitted in Souper's text format:
|
||||||
|
/// https://github.com/google/souper
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
input: PathBuf,
|
||||||
|
|
||||||
|
/// Specify the output file to be used. Use '-' for stdout.
|
||||||
|
#[structopt(short("o"), long("output"), default_value("-"), parse(from_os_str))]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
/// Configure Cranelift settings
|
||||||
|
#[structopt(long("set"))]
|
||||||
|
settings: Vec<String>,
|
||||||
|
|
||||||
|
/// Specify the Cranelift target
|
||||||
|
#[structopt(long("target"))]
|
||||||
|
target: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
let parsed = parse_sets_and_triple(&options.settings, &options.target)?;
|
||||||
let fisa = parsed.as_fisa();
|
let fisa = parsed.as_fisa();
|
||||||
if fisa.isa.is_none() {
|
if fisa.isa.is_none() {
|
||||||
anyhow::bail!("`souper-harvest` requires a target isa");
|
anyhow::bail!("`souper-harvest` requires a target isa");
|
||||||
}
|
}
|
||||||
|
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut input: Box<dyn io::BufRead> = match input {
|
let mut input: Box<dyn io::BufRead> = if options.input == Path::new("-") {
|
||||||
"-" => Box::new(stdin.lock()),
|
Box::new(stdin.lock())
|
||||||
_ => Box::new(io::BufReader::new(
|
} else {
|
||||||
fs::File::open(input).context("failed to open input file")?,
|
Box::new(io::BufReader::new(
|
||||||
)),
|
fs::File::open(&options.input).context("failed to open input file")?,
|
||||||
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output: Box<dyn io::Write + Send> = match output {
|
let mut output: Box<dyn io::Write + Send> = if options.output == Path::new("-") {
|
||||||
"-" => Box::new(io::stdout()),
|
Box::new(io::stdout())
|
||||||
_ => Box::new(io::BufWriter::new(
|
} else {
|
||||||
fs::File::create(output).context("failed to create output file")?,
|
Box::new(io::BufWriter::new(
|
||||||
)),
|
fs::File::create(&options.output).context("failed to create output file")?,
|
||||||
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut contents = vec![];
|
let mut contents = vec![];
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub fn run(input: &Path, output: &Path) -> Result<()> {
|
/// Convert Souper optimizations into Peepmatic DSL.
|
||||||
let peepmatic_dsl = if input == Path::new("-") {
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
input: PathBuf,
|
||||||
|
|
||||||
|
/// Specify the output file to be used. Use '-' for stdout.
|
||||||
|
#[structopt(short("o"), long("output"), default_value("-"), parse(from_os_str))]
|
||||||
|
output: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
let peepmatic_dsl = if options.input == Path::new("-") {
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let mut stdin = stdin.lock();
|
let mut stdin = stdin.lock();
|
||||||
let mut souper_dsl = vec![];
|
let mut souper_dsl = vec![];
|
||||||
@@ -13,18 +26,18 @@ pub fn run(input: &Path, output: &Path) -> Result<()> {
|
|||||||
let souper_dsl = String::from_utf8(souper_dsl).context("stdin is not UTF-8: {}")?;
|
let souper_dsl = String::from_utf8(souper_dsl).context("stdin is not UTF-8: {}")?;
|
||||||
peepmatic_souper::convert_str(&souper_dsl, Some(Path::new("stdin")))?
|
peepmatic_souper::convert_str(&souper_dsl, Some(Path::new("stdin")))?
|
||||||
} else {
|
} else {
|
||||||
peepmatic_souper::convert_file(input)?
|
peepmatic_souper::convert_file(&options.input)?
|
||||||
};
|
};
|
||||||
|
|
||||||
if output == Path::new("-") {
|
if options.output == Path::new("-") {
|
||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
stdout
|
stdout
|
||||||
.write_all(peepmatic_dsl.as_bytes())
|
.write_all(peepmatic_dsl.as_bytes())
|
||||||
.context("error writing to stdout")?;
|
.context("error writing to stdout")?;
|
||||||
} else {
|
} else {
|
||||||
std::fs::write(output, peepmatic_dsl.as_bytes())
|
std::fs::write(&options.output, peepmatic_dsl.as_bytes())
|
||||||
.with_context(|| format!("error writing to {}", output.display()))?;
|
.with_context(|| format!("error writing to {}", options.output.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ pub fn parse_sets_and_triple(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all of the files passed as arguments, recursively iterating through directories.
|
/// Iterate over all of the files passed as arguments, recursively iterating through directories.
|
||||||
pub fn iterate_files(files: Vec<String>) -> impl Iterator<Item = PathBuf> {
|
pub fn iterate_files<'a>(files: &'a [PathBuf]) -> impl Iterator<Item = PathBuf> + 'a {
|
||||||
files
|
files
|
||||||
.into_iter()
|
.iter()
|
||||||
.flat_map(WalkDir::new)
|
.flat_map(WalkDir::new)
|
||||||
.filter(|f| match f {
|
.filter(|f| match f {
|
||||||
Ok(d) => {
|
Ok(d) => {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps};
|
use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps};
|
||||||
use crate::utils::parse_sets_and_triple;
|
use crate::utils::parse_sets_and_triple;
|
||||||
use crate::UseTerminalColor;
|
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use cranelift_codegen::ir::DisplayFunctionAnnotations;
|
use cranelift_codegen::ir::DisplayFunctionAnnotations;
|
||||||
use cranelift_codegen::print_errors::{pretty_error, pretty_verifier_error};
|
use cranelift_codegen::print_errors::{pretty_error, pretty_verifier_error};
|
||||||
@@ -21,6 +20,7 @@ use cranelift_wasm::{translate_module, DummyEnvironment, FuncIndex, ReturnMode};
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use structopt::StructOpt;
|
||||||
use term;
|
use term;
|
||||||
|
|
||||||
/// For verbose printing: only print if the `$x` expression is true.
|
/// For verbose printing: only print if the `$x` expression is true.
|
||||||
@@ -60,69 +60,108 @@ macro_rules! vcprint {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(
|
/// Compiles Wasm binary/text into Cranelift IR and then into target language
|
||||||
files: Vec<String>,
|
#[derive(StructOpt)]
|
||||||
use_terminal_color: UseTerminalColor,
|
pub struct Options {
|
||||||
flag_verbose: bool,
|
/// Be more verbose
|
||||||
flag_just_decode: bool,
|
#[structopt(short = "v", long = "verbose")]
|
||||||
flag_check_translation: bool,
|
verbose: bool,
|
||||||
flag_print: bool,
|
|
||||||
flag_print_disasm: bool,
|
/// Print the resulting Cranelift IR
|
||||||
flag_set: &[String],
|
#[structopt(short("p"))]
|
||||||
flag_triple: &str,
|
print: bool,
|
||||||
flag_print_size: bool,
|
|
||||||
flag_report_times: bool,
|
/// Print pass timing report
|
||||||
flag_calc_value_ranges: bool,
|
#[structopt(short("T"))]
|
||||||
) -> Result<()> {
|
report_times: bool,
|
||||||
let parsed = parse_sets_and_triple(flag_set, flag_triple)?;
|
|
||||||
for filename in files {
|
/// Print machine code disassembly
|
||||||
let path = Path::new(&filename);
|
#[structopt(short("D"), long("disasm"))]
|
||||||
|
disasm: bool,
|
||||||
|
|
||||||
|
/// Configure Cranelift settings
|
||||||
|
#[structopt(long("set"))]
|
||||||
|
settings: Vec<String>,
|
||||||
|
|
||||||
|
/// Specify the Cranelift target
|
||||||
|
#[structopt(long("target"))]
|
||||||
|
target: String,
|
||||||
|
|
||||||
|
/// Specify an input file to be used. Use '-' for stdin.
|
||||||
|
#[structopt(parse(from_os_str))]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
|
||||||
|
/// Enable debug output on stderr/stdout
|
||||||
|
#[structopt(short = "d")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
|
/// Print bytecode size
|
||||||
|
#[structopt(short("X"))]
|
||||||
|
print_size: bool,
|
||||||
|
|
||||||
|
/// Juse decode Wasm into Cranelift IR, don't compile it to native code
|
||||||
|
#[structopt(short("t"))]
|
||||||
|
just_decode: bool,
|
||||||
|
|
||||||
|
/// Just checks the correctness of Cranelift IR translated from Wasm
|
||||||
|
#[structopt(short("c"))]
|
||||||
|
check_translation: bool,
|
||||||
|
|
||||||
|
/// Display values' ranges and their locations
|
||||||
|
#[structopt(long("value-ranges"))]
|
||||||
|
value_ranges: bool,
|
||||||
|
|
||||||
|
/// Use colors in output? [options: auto/never/always; default: auto]
|
||||||
|
#[structopt(long("color"), default_value("auto"))]
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
enum Color {
|
||||||
|
Auto,
|
||||||
|
Never,
|
||||||
|
Always,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for Color {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
match s.as_str() {
|
||||||
|
"auto" => Ok(Color::Auto),
|
||||||
|
"never" => Ok(Color::Never),
|
||||||
|
"always" => Ok(Color::Always),
|
||||||
|
_ => Err(format!("expected auto/never/always, found: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: &Options) -> Result<()> {
|
||||||
|
crate::handle_debug_flag(options.debug);
|
||||||
|
|
||||||
|
let parsed = parse_sets_and_triple(&options.settings, &options.target)?;
|
||||||
|
for path in &options.files {
|
||||||
let name = String::from(path.as_os_str().to_string_lossy());
|
let name = String::from(path.as_os_str().to_string_lossy());
|
||||||
handle_module(
|
handle_module(options, path, &name, parsed.as_fisa())?;
|
||||||
use_terminal_color,
|
|
||||||
flag_verbose,
|
|
||||||
flag_just_decode,
|
|
||||||
flag_check_translation,
|
|
||||||
flag_print,
|
|
||||||
flag_print_size,
|
|
||||||
flag_print_disasm,
|
|
||||||
flag_report_times,
|
|
||||||
flag_calc_value_ranges,
|
|
||||||
&path.to_path_buf(),
|
|
||||||
&name,
|
|
||||||
parsed.as_fisa(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(
|
fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) -> Result<()> {
|
||||||
use_terminal_color: UseTerminalColor,
|
|
||||||
flag_verbose: bool,
|
|
||||||
flag_just_decode: bool,
|
|
||||||
flag_check_translation: bool,
|
|
||||||
flag_print: bool,
|
|
||||||
flag_print_size: bool,
|
|
||||||
flag_print_disasm: bool,
|
|
||||||
flag_report_times: bool,
|
|
||||||
flag_calc_value_ranges: bool,
|
|
||||||
path: &PathBuf,
|
|
||||||
name: &str,
|
|
||||||
fisa: FlagsOrIsa,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut terminal = term::stdout().unwrap();
|
let mut terminal = term::stdout().unwrap();
|
||||||
let use_color = terminal.supports_color() && use_terminal_color == UseTerminalColor::Auto
|
let use_color =
|
||||||
|| use_terminal_color == UseTerminalColor::Always;
|
terminal.supports_color() && options.color == Color::Auto || options.color == Color::Always;
|
||||||
vcprint!(
|
vcprint!(
|
||||||
flag_verbose,
|
options.verbose,
|
||||||
use_color,
|
use_color,
|
||||||
terminal,
|
terminal,
|
||||||
term::color::YELLOW,
|
term::color::YELLOW,
|
||||||
"Handling: "
|
"Handling: "
|
||||||
);
|
);
|
||||||
vprintln!(flag_verbose, "\"{}\"", name);
|
vprintln!(options.verbose, "\"{}\"", name);
|
||||||
vcprint!(
|
vcprint!(
|
||||||
flag_verbose,
|
options.verbose,
|
||||||
use_color,
|
use_color,
|
||||||
terminal,
|
terminal,
|
||||||
term::color::MAGENTA,
|
term::color::MAGENTA,
|
||||||
@@ -148,15 +187,21 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let debug_info = flag_calc_value_ranges;
|
let debug_info = options.value_ranges;
|
||||||
let mut dummy_environ =
|
let mut dummy_environ =
|
||||||
DummyEnvironment::new(isa.frontend_config(), ReturnMode::NormalReturns, debug_info);
|
DummyEnvironment::new(isa.frontend_config(), ReturnMode::NormalReturns, debug_info);
|
||||||
translate_module(&module_binary, &mut dummy_environ)?;
|
translate_module(&module_binary, &mut dummy_environ)?;
|
||||||
|
|
||||||
vcprintln!(flag_verbose, use_color, terminal, term::color::GREEN, "ok");
|
vcprintln!(
|
||||||
|
options.verbose,
|
||||||
|
use_color,
|
||||||
|
terminal,
|
||||||
|
term::color::GREEN,
|
||||||
|
"ok"
|
||||||
|
);
|
||||||
|
|
||||||
if flag_just_decode {
|
if options.just_decode {
|
||||||
if !flag_print {
|
if !options.print {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,22 +215,22 @@ fn handle_module(
|
|||||||
println!("; Selected as wasm start function");
|
println!("; Selected as wasm start function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(options.verbose, "");
|
||||||
for export_name in
|
for export_name in
|
||||||
&dummy_environ.info.functions[FuncIndex::new(func_index)].export_names
|
&dummy_environ.info.functions[FuncIndex::new(func_index)].export_names
|
||||||
{
|
{
|
||||||
println!("; Exported as \"{}\"", export_name);
|
println!("; Exported as \"{}\"", export_name);
|
||||||
}
|
}
|
||||||
println!("{}", context.func.display(None));
|
println!("{}", context.func.display(None));
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(options.verbose, "");
|
||||||
}
|
}
|
||||||
let _ = terminal.reset();
|
let _ = terminal.reset();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_check_translation {
|
if options.check_translation {
|
||||||
vcprint!(
|
vcprint!(
|
||||||
flag_verbose,
|
options.verbose,
|
||||||
use_color,
|
use_color,
|
||||||
terminal,
|
terminal,
|
||||||
term::color::MAGENTA,
|
term::color::MAGENTA,
|
||||||
@@ -193,7 +238,7 @@ fn handle_module(
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
vcprint!(
|
vcprint!(
|
||||||
flag_verbose,
|
options.verbose,
|
||||||
use_color,
|
use_color,
|
||||||
terminal,
|
terminal,
|
||||||
term::color::MAGENTA,
|
term::color::MAGENTA,
|
||||||
@@ -201,8 +246,8 @@ fn handle_module(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_print_size {
|
if options.print_size {
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(options.verbose, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_func_imports = dummy_environ.get_num_func_imports();
|
let num_func_imports = dummy_environ.get_num_func_imports();
|
||||||
@@ -214,10 +259,10 @@ fn handle_module(
|
|||||||
let mut saved_sizes = None;
|
let mut saved_sizes = None;
|
||||||
let func_index = num_func_imports + def_index.index();
|
let func_index = num_func_imports + def_index.index();
|
||||||
let mut mem = vec![];
|
let mut mem = vec![];
|
||||||
let mut relocs = PrintRelocs::new(flag_print);
|
let mut relocs = PrintRelocs::new(options.print);
|
||||||
let mut traps = PrintTraps::new(flag_print);
|
let mut traps = PrintTraps::new(options.print);
|
||||||
let mut stack_maps = PrintStackMaps::new(flag_print);
|
let mut stack_maps = PrintStackMaps::new(options.print);
|
||||||
if flag_check_translation {
|
if options.check_translation {
|
||||||
if let Err(errors) = context.verify(fisa) {
|
if let Err(errors) = context.verify(fisa) {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"{}",
|
"{}",
|
||||||
@@ -229,7 +274,7 @@ fn handle_module(
|
|||||||
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps, &mut stack_maps)
|
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps, &mut stack_maps)
|
||||||
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, fisa.isa, err)))?;
|
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, fisa.isa, err)))?;
|
||||||
|
|
||||||
if flag_print_size {
|
if options.print_size {
|
||||||
println!(
|
println!(
|
||||||
"Function #{} code size: {} bytes",
|
"Function #{} code size: {} bytes",
|
||||||
func_index, code_info.total_size,
|
func_index, code_info.total_size,
|
||||||
@@ -242,7 +287,7 @@ fn handle_module(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_print_disasm {
|
if options.disasm {
|
||||||
saved_sizes = Some((
|
saved_sizes = Some((
|
||||||
code_info.code_size,
|
code_info.code_size,
|
||||||
code_info.jumptables_size + code_info.rodata_size,
|
code_info.jumptables_size + code_info.rodata_size,
|
||||||
@@ -250,8 +295,8 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_print {
|
if options.print {
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(options.verbose, "");
|
||||||
if let Some(start_func) = dummy_environ.info.start_func {
|
if let Some(start_func) = dummy_environ.info.start_func {
|
||||||
if func_index == start_func.index() {
|
if func_index == start_func.index() {
|
||||||
println!("; Selected as wasm start function");
|
println!("; Selected as wasm start function");
|
||||||
@@ -262,7 +307,7 @@ fn handle_module(
|
|||||||
{
|
{
|
||||||
println!("; Exported as \"{}\"", export_name);
|
println!("; Exported as \"{}\"", export_name);
|
||||||
}
|
}
|
||||||
let value_ranges = if flag_calc_value_ranges {
|
let value_ranges = if options.value_ranges {
|
||||||
Some(
|
Some(
|
||||||
context
|
context
|
||||||
.build_value_labels_ranges(isa)
|
.build_value_labels_ranges(isa)
|
||||||
@@ -278,7 +323,7 @@ fn handle_module(
|
|||||||
value_ranges: value_ranges.as_ref(),
|
value_ranges: value_ranges.as_ref(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(options.verbose, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((code_size, rodata_size)) = saved_sizes {
|
if let Some((code_size, rodata_size)) = saved_sizes {
|
||||||
@@ -296,16 +341,22 @@ fn handle_module(
|
|||||||
context.clear();
|
context.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !flag_check_translation && flag_print_size {
|
if !options.check_translation && options.print_size {
|
||||||
println!("Total module code size: {} bytes", total_module_code_size);
|
println!("Total module code size: {} bytes", total_module_code_size);
|
||||||
let total_bytecode_size: usize = dummy_environ.func_bytecode_sizes.iter().sum();
|
let total_bytecode_size: usize = dummy_environ.func_bytecode_sizes.iter().sum();
|
||||||
println!("Total module bytecode size: {} bytes", total_bytecode_size);
|
println!("Total module bytecode size: {} bytes", total_bytecode_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag_report_times {
|
if options.report_times {
|
||||||
println!("{}", timing::take_current());
|
println!("{}", timing::take_current());
|
||||||
}
|
}
|
||||||
|
|
||||||
vcprintln!(flag_verbose, use_color, terminal, term::color::GREEN, "ok");
|
vcprintln!(
|
||||||
|
options.verbose,
|
||||||
|
use_color,
|
||||||
|
terminal,
|
||||||
|
term::color::GREEN,
|
||||||
|
"ok"
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user