waffle/src/bin/waffle-util.rs

123 lines
3.8 KiB
Rust
Raw Normal View History

//! WAFFLE command-line tool.
use anyhow::Result;
use log::debug;
use std::path::PathBuf;
use structopt::StructOpt;
2023-02-23 20:40:25 -06:00
use waffle::InterpContext;
2023-02-16 18:20:54 -06:00
use waffle::{FrontendOptions, Module};
#[derive(Debug, StructOpt)]
#[structopt(name = "waffle-util", about = "WAFFLE utility.")]
struct Options {
#[structopt(short, long)]
debug: bool,
2022-12-02 13:58:04 -06:00
#[structopt(
help = "Do basic optimizations: GVN and const-prop",
long = "basic-opts"
)]
basic_opts: bool,
2023-02-16 18:20:54 -06:00
#[structopt(
help = "Enable parsing of debug-info from input",
short = "g",
long = "debug-info"
)]
debug_info: bool,
2022-12-02 13:58:04 -06:00
#[structopt(help = "Transform to maximal SSA", long = "max-ssa")]
max_ssa: bool,
#[structopt(subcommand)]
command: Command,
}
#[derive(Debug, StructOpt)]
enum Command {
#[structopt(name = "print-ir", about = "Parse Wasm and print resulting IR")]
PrintIR {
#[structopt(help = "Wasm file to parse")]
wasm: PathBuf,
},
2021-12-24 16:12:49 -06:00
#[structopt(name = "roundtrip", about = "Round-trip Wasm through IR")]
RoundTrip {
#[structopt(help = "Wasm file to parse", short = "i")]
input: PathBuf,
#[structopt(help = "Wasm file to produce", short = "o")]
output: PathBuf,
},
2023-02-23 20:40:25 -06:00
#[structopt(name = "interp", about = "Interpret Waffle IR from Wasm")]
Interp {
#[structopt(help = "Wasm file to parse", short = "i")]
input: PathBuf,
},
}
2023-02-07 19:31:52 -06:00
fn apply_options(opts: &Options, module: &mut Module) -> Result<()> {
2023-02-14 21:24:03 -06:00
module.expand_all_funcs()?;
2023-02-07 19:31:52 -06:00
if opts.basic_opts {
module.per_func_body(|body| body.optimize());
}
if opts.max_ssa {
module.per_func_body(|body| body.convert_to_max_ssa());
}
Ok(())
}
fn main() -> Result<()> {
let opts = Options::from_args();
let mut logger = env_logger::Builder::from_default_env();
if opts.debug {
logger.filter_level(log::LevelFilter::Debug);
}
let _ = logger.try_init();
2023-02-16 18:20:54 -06:00
let mut options = FrontendOptions::default();
options.debug = opts.debug_info;
2023-02-07 19:31:52 -06:00
match &opts.command {
Command::PrintIR { wasm } => {
let bytes = std::fs::read(wasm)?;
debug!("Loaded {} bytes of Wasm data", bytes.len());
2023-02-16 18:20:54 -06:00
let mut module = Module::from_wasm_bytes(&bytes[..], &options)?;
2023-02-07 19:31:52 -06:00
apply_options(&opts, &mut module)?;
2022-11-02 14:38:45 -05:00
println!("{}", module.display());
}
2021-12-24 16:12:49 -06:00
Command::RoundTrip { input, output } => {
let bytes = std::fs::read(input)?;
debug!("Loaded {} bytes of Wasm data", bytes.len());
2023-02-16 18:20:54 -06:00
let mut module = Module::from_wasm_bytes(&bytes[..], &options)?;
2023-02-07 19:31:52 -06:00
apply_options(&opts, &mut module)?;
2022-10-27 00:15:15 -05:00
let produced = module.to_wasm_bytes()?;
2021-12-24 16:12:49 -06:00
std::fs::write(output, &produced[..])?;
}
2023-02-23 20:40:25 -06:00
Command::Interp { input } => {
let bytes = std::fs::read(input)?;
debug!("Loaded {} bytes of Wasm data", bytes.len());
let mut module = Module::from_wasm_bytes(&bytes[..], &options)?;
apply_options(&opts, &mut module)?;
// Ensure all functions are expanded -- this is necessary
// for interpretation.
module.expand_all_funcs()?;
let mut ctx = InterpContext::new(&module);
debug!("Calling start function");
if let Some(start) = module.start_func {
ctx.call(&module, start, &[]).unwrap();
}
// Find a function called `_start`, if any.
if let Some(waffle::Export {
kind: waffle::ExportKind::Func(func),
..
}) = module.exports.iter().find(|e| &e.name == "_start")
{
debug!("Calling _start");
ctx.call(&module, *func, &[]).unwrap();
}
}
}
Ok(())
}