diff --git a/cranelift/src/compile.rs b/cranelift/src/compile.rs new file mode 100644 index 0000000000..2db5d21f85 --- /dev/null +++ b/cranelift/src/compile.rs @@ -0,0 +1,82 @@ +//! CLI tool to compile cretonne IL into native code. +//! +//! Reads IR files into Cretonne IL and compiles it. + +use cton_reader::{parse_options, Location, parse_functions}; +use std::path::PathBuf; +use cretonne::Context; +use cretonne::settings::{self, FlagsOrIsa}; +use cretonne::isa::{self, TargetIsa}; +use std::path::Path; +use utils::{pretty_error, read_to_string}; + +enum OwnedFlagsOrIsa { + Flags(settings::Flags), + Isa(Box), +} + +pub fn run( + files: Vec, + flag_print: bool, + flag_set: Vec, + flag_isa: String, +) -> Result<(), String> { + let mut flag_builder = settings::builder(); + parse_options( + flag_set.iter().map(|x| x.as_str()), + &mut flag_builder, + &Location { line_number: 0 }, + ).map_err(|err| err.to_string())?; + + let mut words = flag_isa.trim().split_whitespace(); + // Look for `isa foo`. + let owned_fisa = if let Some(isa_name) = words.next() { + let isa_builder = isa::lookup(isa_name).map_err(|err| match err { + isa::LookupError::Unknown => format!("unknown ISA '{}'", isa_name), + isa::LookupError::Unsupported => format!("support for ISA '{}' not enabled", isa_name), + })?; + OwnedFlagsOrIsa::Isa(isa_builder.finish(settings::Flags::new(&flag_builder))) + } else { + OwnedFlagsOrIsa::Flags(settings::Flags::new(&flag_builder)) + }; + let fisa = match owned_fisa { + OwnedFlagsOrIsa::Flags(ref flags) => FlagsOrIsa::from(flags), + OwnedFlagsOrIsa::Isa(ref isa) => FlagsOrIsa::from(&**isa), + }; + + for filename in files { + let path = Path::new(&filename); + let name = String::from(path.as_os_str().to_string_lossy()); + handle_module(flag_print, path.to_path_buf(), name, &fisa)?; + } + Ok(()) +} + +fn handle_module( + flag_print: bool, + path: PathBuf, + name: String, + fisa: &FlagsOrIsa, +) -> Result<(), String> { + let buffer = read_to_string(&path).map_err( + |e| format!("{}: {}", name, e), + )?; + let items = parse_functions(&buffer).map_err( + |e| format!("{}: {}", name, e), + )?; + for func in items.into_iter() { + let mut context = Context::new(); + context.func = func; + if let Some(isa) = fisa.isa { + context.compile(isa).map_err(|err| { + pretty_error(&context.func, fisa.isa, err) + })?; + } else { + return Err(String::from("compilation requires a target isa")); + } + if flag_print { + println!("{}", context.func.display(fisa.isa)); + } + } + Ok(()) +} diff --git a/cranelift/src/cton-util.rs b/cranelift/src/cton-util.rs index ac0a25c698..b08fa8cde3 100644 --- a/cranelift/src/cton-util.rs +++ b/cranelift/src/cton-util.rs @@ -21,6 +21,7 @@ mod cat; mod print_cfg; mod rsfilecheck; mod wasm; +mod compile; const USAGE: &str = " Cretonne code generator utility @@ -30,6 +31,7 @@ Usage: cton-util cat ... cton-util filecheck [-v] cton-util print-cfg ... + cton-util compile [-vp] [--set ]... [--isa ] ... cton-util wasm [-ctvp] [--set ]... [--isa ] ... cton-util --help | --version @@ -53,6 +55,7 @@ struct Args { cmd_cat: bool, cmd_filecheck: bool, cmd_print_cfg: bool, + cmd_compile: bool, cmd_wasm: bool, arg_file: Vec, flag_just_decode: bool, @@ -86,6 +89,8 @@ fn cton_util() -> CommandResult { rsfilecheck::run(args.arg_file, args.flag_verbose) } else if args.cmd_print_cfg { print_cfg::run(args.arg_file) + } else if args.cmd_compile { + compile::run(args.arg_file, args.flag_print, args.flag_set, args.flag_isa) } else if args.cmd_wasm { wasm::run( args.arg_file,