The result of the emitter is a vector of bytes holding machine code, jump tables, and (in the future) other read-only data. Some clients, notably Firefox's Wasm compiler, needs to separate the machine code from the data in order to insert more code directly after the code generated by Cranelift. To make such separation possible, we record more information about the emitted bytes: the sizes of each of the sections of code, jump tables, and read-only data, as well as the locations within the code that reference (PC-relatively) the jump tables and read-only data.
94 lines
2.6 KiB
Rust
94 lines
2.6 KiB
Rust
//! CLI tool to read Cranelift IR files and compile them into native code.
|
|
|
|
use crate::disasm::{print_all, PrintRelocs, PrintTraps};
|
|
use crate::utils::{parse_sets_and_triple, read_to_string};
|
|
use cranelift_codegen::print_errors::pretty_error;
|
|
use cranelift_codegen::settings::FlagsOrIsa;
|
|
use cranelift_codegen::timing;
|
|
use cranelift_codegen::Context;
|
|
use cranelift_reader::parse_test;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
pub fn run(
|
|
files: Vec<String>,
|
|
flag_print: bool,
|
|
flag_disasm: bool,
|
|
flag_report_times: bool,
|
|
flag_set: &[String],
|
|
flag_isa: &str,
|
|
) -> Result<(), String> {
|
|
let parsed = parse_sets_and_triple(flag_set, flag_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,
|
|
flag_disasm,
|
|
flag_report_times,
|
|
&path.to_path_buf(),
|
|
&name,
|
|
parsed.as_fisa(),
|
|
)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn handle_module(
|
|
flag_print: bool,
|
|
flag_disasm: bool,
|
|
flag_report_times: bool,
|
|
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, None, None).map_err(|e| format!("{}: {}", name, e))?;
|
|
|
|
// If we have an isa from the command-line, use that. Otherwise if the
|
|
// file contains a unique isa, use that.
|
|
let isa = if let Some(isa) = fisa.isa {
|
|
isa
|
|
} else if let Some(isa) = test_file.isa_spec.unique_isa() {
|
|
isa
|
|
} else {
|
|
return Err(String::from("compilation requires a target isa"));
|
|
};
|
|
|
|
for (func, _) in test_file.functions {
|
|
let mut context = Context::new();
|
|
context.func = func;
|
|
|
|
let mut relocs = PrintRelocs::new(flag_print);
|
|
let mut traps = PrintTraps::new(flag_print);
|
|
let mut mem = vec![];
|
|
|
|
// Compile and encode the result to machine code.
|
|
let code_info = context
|
|
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps)
|
|
.map_err(|err| pretty_error(&context.func, Some(isa), err))?;
|
|
|
|
if flag_print {
|
|
println!("{}", context.func.display(isa));
|
|
}
|
|
|
|
if flag_disasm {
|
|
print_all(
|
|
isa,
|
|
&mem,
|
|
code_info.code_size,
|
|
code_info.jumptables_size + code_info.rodata_size,
|
|
&relocs,
|
|
&traps,
|
|
)?;
|
|
}
|
|
}
|
|
|
|
if flag_report_times {
|
|
print!("{}", timing::take_current());
|
|
}
|
|
|
|
Ok(())
|
|
}
|