Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/src/compile.rs
1690 views
1
//! CLI tool to read Cranelift IR files and compile them into native code.
2
3
use crate::disasm::print_all;
4
use crate::utils::read_to_string;
5
use anyhow::{Context as _, Result};
6
use clap::Parser;
7
use cranelift_codegen::Context;
8
use cranelift_codegen::print_errors::pretty_error;
9
use cranelift_codegen::settings::FlagsOrIsa;
10
use cranelift_codegen::timing;
11
use cranelift_reader::OwnedFlagsOrIsa;
12
use cranelift_reader::{ParseOptions, parse_sets_and_triple, parse_test};
13
use std::path::Path;
14
use std::path::PathBuf;
15
16
/// Compiles Cranelift IR into target language
17
#[derive(Parser)]
18
pub struct Options {
19
/// Print the resulting Cranelift IR
20
#[arg(short)]
21
print: bool,
22
23
/// Print pass timing report
24
#[arg(short = 'T')]
25
report_times: bool,
26
27
/// Print machine code disassembly
28
#[arg(short = 'D', long)]
29
disasm: bool,
30
31
/// Configure Cranelift settings
32
#[arg(long = "set")]
33
settings: Vec<String>,
34
35
/// Specify the Cranelift target
36
#[arg(long = "target")]
37
target: String,
38
39
/// Specify an input file to be used. Use '-' for stdin.
40
files: Vec<PathBuf>,
41
42
/// Output object file
43
#[arg(short = 'o', long = "output")]
44
output: Option<PathBuf>,
45
}
46
47
pub fn run(options: &Options) -> Result<()> {
48
let parsed = parse_sets_and_triple(&options.settings, &options.target)?;
49
50
let mut module = match (&options.output, &parsed) {
51
(Some(output), OwnedFlagsOrIsa::Isa(isa)) => {
52
let builder = cranelift_object::ObjectBuilder::new(
53
isa.clone(),
54
output
55
.file_name()
56
.and_then(|s| s.to_str())
57
.unwrap_or("a.out"),
58
cranelift_module::default_libcall_names(),
59
)?;
60
Some(cranelift_object::ObjectModule::new(builder))
61
}
62
_ => None,
63
};
64
65
for path in &options.files {
66
let name = String::from(path.as_os_str().to_string_lossy());
67
handle_module(options, path, &name, parsed.as_fisa(), module.as_mut())?;
68
}
69
70
if let (Some(module), Some(output)) = (module, &options.output) {
71
let bytes = module.finish().emit()?;
72
std::fs::write(output, bytes)?;
73
}
74
75
Ok(())
76
}
77
78
fn handle_module(
79
options: &Options,
80
path: &Path,
81
name: &str,
82
fisa: FlagsOrIsa,
83
module: Option<&mut impl cranelift_module::Module>,
84
) -> Result<()> {
85
let buffer = read_to_string(&path)?;
86
let test_file = parse_test(&buffer, ParseOptions::default())
87
.with_context(|| format!("failed to parse {name}"))?;
88
89
// If we have an isa from the command-line, use that. Otherwise if the
90
// file contains a unique isa, use that.
91
let isa = fisa.isa.or(test_file.isa_spec.unique_isa());
92
93
let isa = match isa {
94
None => anyhow::bail!("compilation requires a target isa"),
95
Some(isa) => isa,
96
};
97
98
for (func, _) in test_file.functions {
99
let mut context = Context::new();
100
context.func = func;
101
102
// Compile and encode the result to machine code.
103
let compiled_code = context
104
.compile(isa, &mut Default::default())
105
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?;
106
let code_info = compiled_code.code_info();
107
108
if let Some(&mut ref mut module) = module {
109
let name = context.func.name.to_string();
110
let fid = module.declare_function(
111
&name,
112
cranelift_module::Linkage::Export,
113
&context.func.signature,
114
)?;
115
module.define_function_with_control_plane(
116
fid,
117
&mut context,
118
&mut Default::default(),
119
)?;
120
}
121
122
if options.print {
123
println!("{}", context.func.display());
124
}
125
126
if options.disasm {
127
let result = context.compiled_code().unwrap();
128
print_all(
129
isa,
130
&context.func,
131
context.compiled_code().unwrap().code_buffer(),
132
code_info.total_size,
133
options.print,
134
result.buffer.relocs(),
135
result.buffer.traps(),
136
)?;
137
}
138
}
139
140
if options.report_times {
141
print!("{}", timing::take_current());
142
}
143
144
Ok(())
145
}
146
147