clif-util: Use anyhow::Error for errors instead of String
Also does the same for `cranelift-filetests`.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::disasm::{PrintRelocs, PrintStackMaps, PrintTraps};
|
||||
use crate::utils::{parse_sets_and_triple, read_to_string};
|
||||
use anyhow::{Context as _, Result};
|
||||
use cranelift_codegen::cursor::{Cursor, FuncCursor};
|
||||
use cranelift_codegen::flowgraph::ControlFlowGraph;
|
||||
use cranelift_codegen::ir::types::{F32, F64};
|
||||
@@ -13,25 +14,19 @@ use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_reader::{parse_test, ParseOptions};
|
||||
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||
|
||||
pub fn run(
|
||||
filename: &str,
|
||||
flag_set: &[String],
|
||||
flag_isa: &str,
|
||||
verbose: bool,
|
||||
) -> Result<(), String> {
|
||||
pub fn run(filename: &str, flag_set: &[String], flag_isa: &str, verbose: bool) -> Result<()> {
|
||||
let parsed = parse_sets_and_triple(flag_set, flag_isa)?;
|
||||
let fisa = parsed.as_fisa();
|
||||
|
||||
let path = Path::new(&filename).to_path_buf();
|
||||
|
||||
let buffer = read_to_string(&path).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
let test_file =
|
||||
parse_test(&buffer, ParseOptions::default()).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
let buffer = read_to_string(&path)?;
|
||||
let test_file = parse_test(&buffer, ParseOptions::default())
|
||||
.with_context(|| format!("failed to parse {}", filename))?;
|
||||
|
||||
// If we have an isa from the command-line, use that. Otherwise if the
|
||||
// file contains a unique isa, use that.
|
||||
@@ -40,7 +35,7 @@ pub fn run(
|
||||
} else if let Some(isa) = test_file.isa_spec.unique_isa() {
|
||||
isa
|
||||
} else {
|
||||
return Err(String::from("compilation requires a target isa"));
|
||||
anyhow::bail!("compilation requires a target isa");
|
||||
};
|
||||
|
||||
std::env::set_var("RUST_BACKTRACE", "0"); // Disable backtraces to reduce verbosity
|
||||
@@ -833,20 +828,11 @@ fn try_resolve_aliases(context: &mut CrashCheckContext, func: &mut Function) {
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce(
|
||||
isa: &dyn TargetIsa,
|
||||
mut func: Function,
|
||||
verbose: bool,
|
||||
) -> Result<(Function, String), String> {
|
||||
fn reduce(isa: &dyn TargetIsa, mut func: Function, verbose: bool) -> Result<(Function, String)> {
|
||||
let mut context = CrashCheckContext::new(isa);
|
||||
|
||||
match context.check_for_crash(&func) {
|
||||
CheckResult::Succeed => {
|
||||
return Err(
|
||||
"Given function compiled successfully or gave a verifier error.".to_string(),
|
||||
);
|
||||
}
|
||||
CheckResult::Crash(_) => {}
|
||||
if let CheckResult::Succeed = context.check_for_crash(&func) {
|
||||
anyhow::bail!("Given function compiled successfully or gave a verifier error.");
|
||||
}
|
||||
|
||||
try_resolve_aliases(&mut context, &mut func);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
//! normalizing formatting and removing comments.
|
||||
|
||||
use crate::utils::read_to_string;
|
||||
use crate::CommandResult;
|
||||
use anyhow::{Context, Result};
|
||||
use cranelift_reader::parse_functions;
|
||||
|
||||
pub fn run(files: &[String]) -> CommandResult {
|
||||
pub fn run(files: &[String]) -> Result<()> {
|
||||
for (i, f) in files.iter().enumerate() {
|
||||
if i != 0 {
|
||||
println!();
|
||||
@@ -17,9 +17,10 @@ pub fn run(files: &[String]) -> CommandResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cat_one(filename: &str) -> CommandResult {
|
||||
let buffer = read_to_string(&filename).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
let items = parse_functions(&buffer).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
fn cat_one(filename: &str) -> Result<()> {
|
||||
let buffer = read_to_string(&filename)?;
|
||||
let items =
|
||||
parse_functions(&buffer).with_context(|| format!("failed to parse {}", filename))?;
|
||||
|
||||
for (idx, func) in items.into_iter().enumerate() {
|
||||
if idx != 0 {
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
use clap::{arg_enum, 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;
|
||||
@@ -37,9 +35,6 @@ mod souper_to_peepmatic;
|
||||
#[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("-")
|
||||
@@ -199,7 +194,7 @@ fn handle_debug_flag(debug: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let app_cmds = App::new("Cranelift code generator utility")
|
||||
.version(VERSION)
|
||||
.subcommand(
|
||||
@@ -276,10 +271,10 @@ fn main() {
|
||||
.arg(add_set_flag()),
|
||||
);
|
||||
|
||||
let res_util = match app_cmds.get_matches().subcommand() {
|
||||
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")))
|
||||
cat::run(&get_vec(rest_cmd.values_of("file")))?
|
||||
}
|
||||
("test", Some(rest_cmd)) => {
|
||||
handle_debug_flag(rest_cmd.is_present("debug"));
|
||||
@@ -288,23 +283,21 @@ fn main() {
|
||||
rest_cmd.is_present("time-passes"),
|
||||
&get_vec(rest_cmd.values_of("file")),
|
||||
)
|
||||
.map(|_time| ())
|
||||
.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"),
|
||||
)
|
||||
.map(|_time| ())
|
||||
)?;
|
||||
}
|
||||
("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"),
|
||||
)
|
||||
.map(|_time| ())
|
||||
)?;
|
||||
}
|
||||
("pass", Some(rest_cmd)) => {
|
||||
handle_debug_flag(rest_cmd.is_present("debug"));
|
||||
@@ -322,11 +315,11 @@ fn main() {
|
||||
target_val,
|
||||
rest_cmd.value_of("single-file").unwrap(),
|
||||
)
|
||||
.map(|_time| ())
|
||||
.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")))
|
||||
print_cfg::run(&get_vec(rest_cmd.values_of("file")))?;
|
||||
}
|
||||
("compile", Some(rest_cmd)) => {
|
||||
handle_debug_flag(rest_cmd.is_present("debug"));
|
||||
@@ -343,13 +336,13 @@ fn main() {
|
||||
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;
|
||||
@@ -368,13 +361,13 @@ fn main() {
|
||||
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
|
||||
{
|
||||
anyhow::bail!("Error: clif-util was compiled without wasm support.");
|
||||
}
|
||||
}
|
||||
("bugpoint", Some(rest_cmd)) => {
|
||||
let mut target_val: &str = "";
|
||||
@@ -387,7 +380,7 @@ fn main() {
|
||||
&get_vec(rest_cmd.values_of("set")),
|
||||
target_val,
|
||||
rest_cmd.is_present("verbose"),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
("souper-to-peepmatic", Some(rest_cmd)) => {
|
||||
#[cfg(feature = "peepmatic-souper")]
|
||||
@@ -396,15 +389,15 @@ fn main() {
|
||||
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"))]
|
||||
{
|
||||
Err(
|
||||
"Error: clif-util was compiled without support for the `souper-to-peepmatic` \
|
||||
anyhow::bail!(
|
||||
"Error: clif-util was compiled without suport for the `souper-to-peepmatic` \
|
||||
subcommand"
|
||||
.into(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
("souper-harvest", Some(rest_cmd)) => {
|
||||
@@ -415,23 +408,16 @@ fn main() {
|
||||
rest_cmd.value_of("single-file").unwrap(),
|
||||
rest_cmd.value_of("output").unwrap(),
|
||||
&get_vec(rest_cmd.values_of("set")),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "souper-harvest"))]
|
||||
{
|
||||
Err("clif-util was compiled without `souper-harvest` support".into())
|
||||
anyhow::bail!("clif-util was compiled without `souper-harvest` support");
|
||||
}
|
||||
}
|
||||
_ => 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);
|
||||
_ => anyhow::bail!("Invalid subcommand.".to_owned()),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps};
|
||||
use crate::utils::{parse_sets_and_triple, read_to_string};
|
||||
use anyhow::{Context as _, Result};
|
||||
use cranelift_codegen::print_errors::pretty_error;
|
||||
use cranelift_codegen::settings::FlagsOrIsa;
|
||||
use cranelift_codegen::timing;
|
||||
@@ -17,7 +18,7 @@ pub fn run(
|
||||
flag_report_times: bool,
|
||||
flag_set: &[String],
|
||||
flag_isa: &str,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
let parsed = parse_sets_and_triple(flag_set, flag_isa)?;
|
||||
|
||||
for filename in files {
|
||||
@@ -42,17 +43,17 @@ fn handle_module(
|
||||
path: &PathBuf,
|
||||
name: &str,
|
||||
fisa: FlagsOrIsa,
|
||||
) -> Result<(), String> {
|
||||
let buffer = read_to_string(&path).map_err(|e| format!("{}: {}", name, e))?;
|
||||
let test_file =
|
||||
parse_test(&buffer, ParseOptions::default()).map_err(|e| format!("{}: {}", name, e))?;
|
||||
) -> Result<()> {
|
||||
let buffer = read_to_string(&path)?;
|
||||
let test_file = parse_test(&buffer, ParseOptions::default())
|
||||
.with_context(|| format!("failed to parse {}", name))?;
|
||||
|
||||
// If we have an isa from the command-line, use that. Otherwise if the
|
||||
// file contains a unique isa, use that.
|
||||
let isa = fisa.isa.or(test_file.isa_spec.unique_isa());
|
||||
|
||||
if isa.is_none() {
|
||||
return Err(String::from("compilation requires a target isa"));
|
||||
anyhow::bail!("compilation requires a target isa");
|
||||
};
|
||||
|
||||
for (func, _) in test_file.functions {
|
||||
@@ -68,7 +69,9 @@ fn handle_module(
|
||||
// Compile and encode the result to machine code.
|
||||
let code_info = context
|
||||
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps, &mut stack_maps)
|
||||
.map_err(|err| pretty_error(&context.func, Some(isa), err))?;
|
||||
.map_err(|err| {
|
||||
anyhow::anyhow!("{}", pretty_error(&context.func, Some(isa), err))
|
||||
})?;
|
||||
|
||||
if flag_print {
|
||||
println!("{}", context.func.display(isa));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use anyhow::Result;
|
||||
use cfg_if::cfg_if;
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::{binemit, ir};
|
||||
@@ -124,53 +125,52 @@ cfg_if! {
|
||||
use capstone::prelude::*;
|
||||
use target_lexicon::Architecture;
|
||||
|
||||
fn get_disassembler(isa: &dyn TargetIsa) -> Result<Capstone, String> {
|
||||
fn get_disassembler(isa: &dyn TargetIsa) -> Result<Capstone> {
|
||||
let cs = match isa.triple().architecture {
|
||||
Architecture::Riscv32 | Architecture::Riscv64 => {
|
||||
return Err(String::from("No disassembler for RiscV"))
|
||||
anyhow::bail!("No disassembler for RiscV");
|
||||
}
|
||||
Architecture::I386 | Architecture::I586 | Architecture::I686 => Capstone::new()
|
||||
.x86()
|
||||
.mode(arch::x86::ArchMode::Mode32)
|
||||
.build(),
|
||||
.build()?,
|
||||
Architecture::X86_64 => Capstone::new()
|
||||
.x86()
|
||||
.mode(arch::x86::ArchMode::Mode64)
|
||||
.build(),
|
||||
.build()?,
|
||||
Architecture::Arm(arm) => {
|
||||
if arm.is_thumb() {
|
||||
Capstone::new()
|
||||
.arm()
|
||||
.mode(arch::arm::ArchMode::Thumb)
|
||||
.build()
|
||||
.build()?
|
||||
} else {
|
||||
Capstone::new()
|
||||
.arm()
|
||||
.mode(arch::arm::ArchMode::Arm)
|
||||
.build()
|
||||
.build()?
|
||||
}
|
||||
}
|
||||
Architecture::Aarch64 {..} => {
|
||||
let mut cs = Capstone::new()
|
||||
.arm64()
|
||||
.mode(arch::arm64::ArchMode::Arm)
|
||||
.build()
|
||||
.map_err(|err| err.to_string())?;
|
||||
.build()?;
|
||||
// AArch64 uses inline constants rather than a separate constant pool right now.
|
||||
// Without this option, Capstone will stop disassembling as soon as it sees
|
||||
// an inline constant that is not also a valid instruction. With this option,
|
||||
// Capstone will print a `.byte` directive with the bytes of the inline constant
|
||||
// and continue to the next instruction.
|
||||
cs.set_skipdata(true).map_err(|err| err.to_string())?;
|
||||
Ok(cs)
|
||||
cs.set_skipdata(true)?;
|
||||
cs
|
||||
}
|
||||
_ => return Err(String::from("Unknown ISA")),
|
||||
_ => anyhow::bail!("Unknown ISA"),
|
||||
};
|
||||
|
||||
cs.map_err(|err| err.to_string())
|
||||
Ok(cs)
|
||||
}
|
||||
|
||||
pub fn print_disassembly(isa: &dyn TargetIsa, mem: &[u8]) -> Result<(), String> {
|
||||
pub fn print_disassembly(isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> {
|
||||
let cs = get_disassembler(isa)?;
|
||||
|
||||
println!("\nDisassembly of {} bytes:", mem.len());
|
||||
@@ -209,7 +209,7 @@ cfg_if! {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
pub fn print_disassembly(_: &dyn TargetIsa, _: &[u8]) -> Result<(), String> {
|
||||
pub fn print_disassembly(_: &dyn TargetIsa, _: &[u8]) -> Result<()> {
|
||||
println!("\nNo disassembly available.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -224,7 +224,7 @@ pub fn print_all(
|
||||
relocs: &PrintRelocs,
|
||||
traps: &PrintTraps,
|
||||
stack_maps: &PrintStackMaps,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
print_bytes(&mem);
|
||||
print_disassembly(isa, &mem[0..code_size as usize])?;
|
||||
print_readonly_data(&mem[code_size as usize..(code_size + rodata_size) as usize]);
|
||||
|
||||
@@ -10,12 +10,12 @@ use std::{fs, io};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Run files through the Cranelift interpreter, interpreting any functions with annotations.
|
||||
pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
|
||||
pub fn run(files: Vec<String>, flag_print: bool) -> anyhow::Result<()> {
|
||||
let mut total = 0;
|
||||
let mut errors = 0;
|
||||
for file in iterate_files(files) {
|
||||
total += 1;
|
||||
let runner = FileInterpreter::from_path(file).map_err(|e| e.to_string())?;
|
||||
let runner = FileInterpreter::from_path(file)?;
|
||||
match runner.run() {
|
||||
Ok(_) => {
|
||||
if flag_print {
|
||||
@@ -41,8 +41,8 @@ pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
|
||||
|
||||
match errors {
|
||||
0 => Ok(()),
|
||||
1 => Err(String::from("1 failure")),
|
||||
n => Err(format!("{} failures", n)),
|
||||
1 => anyhow::bail!("1 failure"),
|
||||
n => anyhow::bail!("{} failures", n),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
//! in graphviz format.
|
||||
|
||||
use crate::utils::read_to_string;
|
||||
use crate::CommandResult;
|
||||
use anyhow::Result;
|
||||
use cranelift_codegen::cfg_printer::CFGPrinter;
|
||||
use cranelift_reader::parse_functions;
|
||||
|
||||
pub fn run(files: &[String]) -> CommandResult {
|
||||
pub fn run(files: &[String]) -> Result<()> {
|
||||
for (i, f) in files.iter().enumerate() {
|
||||
if i != 0 {
|
||||
println!();
|
||||
@@ -18,9 +18,9 @@ pub fn run(files: &[String]) -> CommandResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_cfg(filename: &str) -> CommandResult {
|
||||
let buffer = read_to_string(filename).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
let items = parse_functions(&buffer).map_err(|e| format!("{}: {}", filename, e))?;
|
||||
fn print_cfg(filename: &str) -> Result<()> {
|
||||
let buffer = read_to_string(filename)?;
|
||||
let items = parse_functions(&buffer)?;
|
||||
|
||||
for (idx, func) in items.into_iter().enumerate() {
|
||||
if idx != 0 {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! CLI tool to compile Cranelift IR files to native code in memory and execute them.
|
||||
|
||||
use crate::utils::{iterate_files, read_to_string};
|
||||
use anyhow::Result;
|
||||
use cranelift_codegen::isa::{CallConv, TargetIsa};
|
||||
use cranelift_filetests::SingleFunctionCompiler;
|
||||
use cranelift_native::builder as host_isa_builder;
|
||||
@@ -8,7 +9,7 @@ use cranelift_reader::{parse_run_command, parse_test, Details, IsaSpec, ParseOpt
|
||||
use std::path::PathBuf;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
|
||||
pub fn run(files: Vec<String>, flag_print: bool) -> Result<()> {
|
||||
let stdin_exist = files.iter().find(|file| *file == "-").is_some();
|
||||
let filtered_files = files
|
||||
.iter()
|
||||
@@ -48,33 +49,33 @@ pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
|
||||
|
||||
match errors {
|
||||
0 => Ok(()),
|
||||
1 => Err(String::from("1 failure")),
|
||||
n => Err(format!("{} failures", n)),
|
||||
1 => anyhow::bail!("1 failure"),
|
||||
n => anyhow::bail!("{} failures", n),
|
||||
}
|
||||
}
|
||||
|
||||
/// Run all functions in a file that are succeeded by "run:" comments
|
||||
fn run_single_file(path: &PathBuf) -> Result<(), String> {
|
||||
let file_contents = read_to_string(&path).map_err(|e| e.to_string())?;
|
||||
fn run_single_file(path: &PathBuf) -> Result<()> {
|
||||
let file_contents = read_to_string(&path)?;
|
||||
run_file_contents(file_contents)
|
||||
}
|
||||
|
||||
/// Main body of `run_single_file` separated for testing
|
||||
fn run_file_contents(file_contents: String) -> Result<(), String> {
|
||||
fn run_file_contents(file_contents: String) -> Result<()> {
|
||||
let options = ParseOptions {
|
||||
default_calling_convention: CallConv::triple_default(&Triple::host()), // use the host's default calling convention
|
||||
..ParseOptions::default()
|
||||
};
|
||||
let test_file = parse_test(&file_contents, options).map_err(|e| e.to_string())?;
|
||||
let test_file = parse_test(&file_contents, options)?;
|
||||
let isa = create_target_isa(&test_file.isa_spec)?;
|
||||
let mut compiler = SingleFunctionCompiler::new(isa);
|
||||
for (func, Details { comments, .. }) in test_file.functions {
|
||||
for comment in comments {
|
||||
if let Some(command) =
|
||||
parse_run_command(comment.text, &func.signature).map_err(|e| e.to_string())?
|
||||
{
|
||||
let compiled_fn = compiler.compile(func.clone()).map_err(|e| e.to_string())?;
|
||||
command.run(|_, args| Ok(compiled_fn.call(args)))?;
|
||||
if let Some(command) = parse_run_command(comment.text, &func.signature)? {
|
||||
let compiled_fn = compiler.compile(func.clone())?;
|
||||
command
|
||||
.run(|_, args| Ok(compiled_fn.call(args)))
|
||||
.map_err(|s| anyhow::anyhow!("{}", s))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,13 +83,16 @@ fn run_file_contents(file_contents: String) -> Result<(), String> {
|
||||
}
|
||||
|
||||
/// Build an ISA based on the current machine running this code (the host)
|
||||
fn create_target_isa(isa_spec: &IsaSpec) -> Result<Box<dyn TargetIsa>, String> {
|
||||
fn create_target_isa(isa_spec: &IsaSpec) -> Result<Box<dyn TargetIsa>> {
|
||||
if let IsaSpec::None(flags) = isa_spec {
|
||||
// build an ISA for the current machine
|
||||
let builder = host_isa_builder()?;
|
||||
let builder = host_isa_builder().map_err(|s| anyhow::anyhow!("{}", s))?;
|
||||
Ok(builder.finish(flags.clone()))
|
||||
} else {
|
||||
Err(String::from("A target ISA was specified in the file but should not have been--only the host ISA can be used for running CLIF files"))
|
||||
anyhow::bail!(
|
||||
"A target ISA was specified in the file but should not have been--only \
|
||||
the host ISA can be used for running CLIF files"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::utils::parse_sets_and_triple;
|
||||
use anyhow::{Context as _, Result};
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_wasm::{DummyEnvironment, ReturnMode};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
@@ -6,32 +7,32 @@ use std::{fs, io};
|
||||
|
||||
static WASM_MAGIC: &[u8] = &[0x00, 0x61, 0x73, 0x6D];
|
||||
|
||||
pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Result<(), String> {
|
||||
pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Result<()> {
|
||||
let parsed = parse_sets_and_triple(flag_set, target)?;
|
||||
let fisa = parsed.as_fisa();
|
||||
if fisa.isa.is_none() {
|
||||
return Err("`souper-harvest` requires a target isa".into());
|
||||
anyhow::bail!("`souper-harvest` requires a target isa");
|
||||
}
|
||||
|
||||
let stdin = io::stdin();
|
||||
let mut input: Box<dyn io::BufRead> = match input {
|
||||
"-" => Box::new(stdin.lock()),
|
||||
_ => Box::new(io::BufReader::new(
|
||||
fs::File::open(input).map_err(|e| format!("failed to open input file: {}", e))?,
|
||||
fs::File::open(input).context("failed to open input file")?,
|
||||
)),
|
||||
};
|
||||
|
||||
let mut output: Box<dyn io::Write + Send> = match output {
|
||||
"-" => Box::new(io::stdout()),
|
||||
_ => Box::new(io::BufWriter::new(
|
||||
fs::File::create(output).map_err(|e| format!("failed to create output file: {}", e))?,
|
||||
fs::File::create(output).context("failed to create output file")?,
|
||||
)),
|
||||
};
|
||||
|
||||
let mut contents = vec![];
|
||||
input
|
||||
.read_to_end(&mut contents)
|
||||
.map_err(|e| format!("failed to read from input file: {}", e))?;
|
||||
.context("failed to read input file")?;
|
||||
|
||||
let funcs = if &contents[..WASM_MAGIC.len()] == WASM_MAGIC {
|
||||
let mut dummy_environ = DummyEnvironment::new(
|
||||
@@ -40,7 +41,7 @@ pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Resu
|
||||
false,
|
||||
);
|
||||
cranelift_wasm::translate_module(&contents, &mut dummy_environ)
|
||||
.map_err(|e| format!("failed to translate Wasm module to clif: {}", e))?;
|
||||
.context("failed to translate Wasm module to clif")?;
|
||||
dummy_environ
|
||||
.info
|
||||
.function_bodies
|
||||
@@ -48,19 +49,17 @@ pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Resu
|
||||
.map(|(_, f)| f.clone())
|
||||
.collect()
|
||||
} else {
|
||||
let contents = String::from_utf8(contents)
|
||||
.map_err(|e| format!("input is not a UTF-8 string: {}", e))?;
|
||||
cranelift_reader::parse_functions(&contents)
|
||||
.map_err(|e| format!("failed to parse clif: {}", e))?
|
||||
let contents = String::from_utf8(contents)?;
|
||||
cranelift_reader::parse_functions(&contents)?
|
||||
};
|
||||
|
||||
let (send, recv) = std::sync::mpsc::channel::<String>();
|
||||
|
||||
let writing_thread = std::thread::spawn(move || -> Result<(), String> {
|
||||
let writing_thread = std::thread::spawn(move || -> Result<()> {
|
||||
for lhs in recv {
|
||||
output
|
||||
.write_all(lhs.as_bytes())
|
||||
.map_err(|e| format!("failed to write to output file: {}", e))?;
|
||||
.context("failed to write to output file")?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
@@ -73,14 +72,14 @@ pub fn run(target: &str, input: &str, output: &str, flag_set: &[String]) -> Resu
|
||||
|
||||
ctx.compute_cfg();
|
||||
ctx.preopt(fisa.isa.unwrap())
|
||||
.map_err(|e| format!("failed to run preopt: {}", e))?;
|
||||
.context("failed to run preopt")?;
|
||||
|
||||
ctx.souper_harvest(send)
|
||||
.map_err(|e| format!("failed to run souper harvester: {}", e))?;
|
||||
.context("failed to run souper harvester")?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Result<(), String>>()?;
|
||||
.collect::<Result<()>>()?;
|
||||
|
||||
match writing_thread.join() {
|
||||
Ok(result) => result?,
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
use anyhow::{Context, Result};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn run(input: &Path, output: &Path) -> Result<(), String> {
|
||||
pub fn run(input: &Path, output: &Path) -> Result<()> {
|
||||
let peepmatic_dsl = if input == Path::new("-") {
|
||||
let stdin = std::io::stdin();
|
||||
let mut stdin = stdin.lock();
|
||||
let mut souper_dsl = vec![];
|
||||
stdin
|
||||
.read_to_end(&mut souper_dsl)
|
||||
.map_err(|e| format!("failed to read from stdin: {}", e))?;
|
||||
let souper_dsl =
|
||||
String::from_utf8(souper_dsl).map_err(|e| format!("stdin is not UTF-8: {}", e))?;
|
||||
peepmatic_souper::convert_str(&souper_dsl, Some(Path::new("stdin")))
|
||||
.map_err(|e| e.to_string())?
|
||||
.context("failed to read from stdin")?;
|
||||
let souper_dsl = String::from_utf8(souper_dsl).context("stdin is not UTF-8: {}")?;
|
||||
peepmatic_souper::convert_str(&souper_dsl, Some(Path::new("stdin")))?
|
||||
} else {
|
||||
peepmatic_souper::convert_file(input).map_err(|e| e.to_string())?
|
||||
peepmatic_souper::convert_file(input)?
|
||||
};
|
||||
|
||||
if output == Path::new("-") {
|
||||
@@ -22,10 +21,10 @@ pub fn run(input: &Path, output: &Path) -> Result<(), String> {
|
||||
let mut stdout = stdout.lock();
|
||||
stdout
|
||||
.write_all(peepmatic_dsl.as_bytes())
|
||||
.map_err(|e| format!("error writing to stdout: {}", e))?;
|
||||
.context("error writing to stdout")?;
|
||||
} else {
|
||||
std::fs::write(output, peepmatic_dsl.as_bytes())
|
||||
.map_err(|e| format!("error writing to {}: {}", output.display(), e))?;
|
||||
.with_context(|| format!("error writing to {}", output.display()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Utility functions.
|
||||
|
||||
use anyhow::Context;
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::settings::{self, FlagsOrIsa};
|
||||
@@ -12,15 +13,19 @@ use target_lexicon::Triple;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
/// Read an entire file into a string.
|
||||
pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
|
||||
pub fn read_to_string<P: AsRef<Path>>(path: P) -> anyhow::Result<String> {
|
||||
let mut buffer = String::new();
|
||||
if path.as_ref() == Path::new("-") {
|
||||
let path = path.as_ref();
|
||||
if path == Path::new("-") {
|
||||
let stdin = io::stdin();
|
||||
let mut stdin = stdin.lock();
|
||||
stdin.read_to_string(&mut buffer)?;
|
||||
stdin
|
||||
.read_to_string(&mut buffer)
|
||||
.context("failed to read stdin to string")?;
|
||||
} else {
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_string(&mut buffer)?;
|
||||
file.read_to_string(&mut buffer)
|
||||
.with_context(|| format!("failed to read {} to string", path.display()))?;
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
@@ -45,7 +50,7 @@ impl OwnedFlagsOrIsa {
|
||||
pub fn parse_sets_and_triple(
|
||||
flag_set: &[String],
|
||||
flag_triple: &str,
|
||||
) -> Result<OwnedFlagsOrIsa, String> {
|
||||
) -> anyhow::Result<OwnedFlagsOrIsa> {
|
||||
let mut flag_builder = settings::builder();
|
||||
|
||||
// Collect unknown system-wide settings, so we can try to parse them as target specific
|
||||
@@ -59,7 +64,7 @@ pub fn parse_sets_and_triple(
|
||||
Err(ParseOptionError::UnknownFlag { name, .. }) => {
|
||||
unknown_settings.push(name);
|
||||
}
|
||||
Err(ParseOptionError::Generic(err)) => return Err(err.to_string()),
|
||||
Err(ParseOptionError::Generic(err)) => return Err(err.into()),
|
||||
Ok(()) => {}
|
||||
}
|
||||
|
||||
@@ -68,14 +73,14 @@ pub fn parse_sets_and_triple(
|
||||
if let Some(triple_name) = words.next() {
|
||||
let triple = match Triple::from_str(triple_name) {
|
||||
Ok(triple) => triple,
|
||||
Err(parse_error) => return Err(parse_error.to_string()),
|
||||
Err(parse_error) => return Err(parse_error.into()),
|
||||
};
|
||||
|
||||
let mut isa_builder = isa::lookup(triple).map_err(|err| match err {
|
||||
isa::LookupError::SupportDisabled => {
|
||||
format!("support for triple '{}' is disabled", triple_name)
|
||||
anyhow::anyhow!("support for triple '{}' is disabled", triple_name)
|
||||
}
|
||||
isa::LookupError::Unsupported => format!(
|
||||
isa::LookupError::Unsupported => anyhow::anyhow!(
|
||||
"support for triple '{}' is not implemented yet",
|
||||
triple_name
|
||||
),
|
||||
@@ -87,21 +92,18 @@ pub fn parse_sets_and_triple(
|
||||
&mut isa_builder,
|
||||
Location { line_number: 0 },
|
||||
)
|
||||
.map_err(|err| ParseError::from(err).to_string())?;
|
||||
.map_err(ParseError::from)?;
|
||||
|
||||
// Apply the ISA-specific settings to `isa_builder`.
|
||||
parse_options(words, &mut isa_builder, Location { line_number: 0 })
|
||||
.map_err(|err| ParseError::from(err).to_string())?;
|
||||
.map_err(ParseError::from)?;
|
||||
|
||||
Ok(OwnedFlagsOrIsa::Isa(
|
||||
isa_builder.finish(settings::Flags::new(flag_builder)),
|
||||
))
|
||||
} else {
|
||||
if !unknown_settings.is_empty() {
|
||||
return Err(format!(
|
||||
"unknown settings: '{}'",
|
||||
unknown_settings.join("', '")
|
||||
));
|
||||
anyhow::bail!("unknown settings: '{}'", unknown_settings.join("', '"));
|
||||
}
|
||||
Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(flag_builder)))
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps};
|
||||
use crate::utils::parse_sets_and_triple;
|
||||
use crate::UseTerminalColor;
|
||||
use anyhow::{Context as _, Result};
|
||||
use cranelift_codegen::ir::DisplayFunctionAnnotations;
|
||||
use cranelift_codegen::print_errors::{pretty_error, pretty_verifier_error};
|
||||
use cranelift_codegen::settings::FlagsOrIsa;
|
||||
@@ -72,7 +73,7 @@ pub fn run(
|
||||
flag_print_size: bool,
|
||||
flag_report_times: bool,
|
||||
flag_calc_value_ranges: bool,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
let parsed = parse_sets_and_triple(flag_set, flag_triple)?;
|
||||
for filename in files {
|
||||
let path = Path::new(&filename);
|
||||
@@ -108,7 +109,7 @@ fn handle_module(
|
||||
path: &PathBuf,
|
||||
name: &str,
|
||||
fisa: FlagsOrIsa,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
let mut terminal = term::stdout().unwrap();
|
||||
let use_color = terminal.supports_color() && use_terminal_color == UseTerminalColor::Auto
|
||||
|| use_terminal_color == UseTerminalColor::Always;
|
||||
@@ -134,27 +135,23 @@ fn handle_module(
|
||||
stdin
|
||||
.lock()
|
||||
.read_to_end(&mut buf)
|
||||
.map_err(|e| e.to_string())?;
|
||||
wat::parse_bytes(&buf)
|
||||
.map_err(|err| format!("{:?}", err))?
|
||||
.into()
|
||||
.context("failed to read stdin")?;
|
||||
wat::parse_bytes(&buf)?.into()
|
||||
} else {
|
||||
wat::parse_file(path).map_err(|err| format!("{:?}", err))?
|
||||
wat::parse_file(path)?
|
||||
};
|
||||
|
||||
let isa = match fisa.isa {
|
||||
Some(isa) => isa,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Error: the wasm command requires an explicit isa.",
|
||||
));
|
||||
anyhow::bail!("Error: the wasm command requires an explicit isa.");
|
||||
}
|
||||
};
|
||||
|
||||
let debug_info = flag_calc_value_ranges;
|
||||
let mut dummy_environ =
|
||||
DummyEnvironment::new(isa.frontend_config(), ReturnMode::NormalReturns, debug_info);
|
||||
translate_module(&module_binary, &mut dummy_environ).map_err(|e| e.to_string())?;
|
||||
translate_module(&module_binary, &mut dummy_environ)?;
|
||||
|
||||
vcprintln!(flag_verbose, use_color, terminal, term::color::GREEN, "ok");
|
||||
|
||||
@@ -222,12 +219,15 @@ fn handle_module(
|
||||
let mut stack_maps = PrintStackMaps::new(flag_print);
|
||||
if flag_check_translation {
|
||||
if let Err(errors) = context.verify(fisa) {
|
||||
return Err(pretty_verifier_error(&context.func, fisa.isa, None, errors));
|
||||
anyhow::bail!(
|
||||
"{}",
|
||||
pretty_verifier_error(&context.func, fisa.isa, None, errors)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let code_info = context
|
||||
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps, &mut stack_maps)
|
||||
.map_err(|err| pretty_error(&context.func, fisa.isa, err))?;
|
||||
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, fisa.isa, err)))?;
|
||||
|
||||
if flag_print_size {
|
||||
println!(
|
||||
|
||||
Reference in New Issue
Block a user