Add a compile command to Wasmtime.

This commit adds a `compile` command to the Wasmtime CLI.

The command can be used to Ahead-Of-Time (AOT) compile WebAssembly modules.

With the `all-arch` feature enabled, AOT compilation can be performed for
non-native architectures (i.e. cross-compilation).

The `Module::compile` method has been added to perform AOT compilation.

A few of the CLI flags relating to "on by default" Wasm features have been
changed to be "--disable-XYZ" flags.

A simple example of using the `wasmtime compile` command:

```text
$ wasmtime compile input.wasm
$ wasmtime input.cwasm
```
This commit is contained in:
Peter Huene
2021-03-24 18:49:33 -07:00
parent 90aa5cf49f
commit 29d366db7b
35 changed files with 1618 additions and 278 deletions

View File

@@ -70,6 +70,72 @@ fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatte
fmtln!(fmt, "}");
}
/// Generates the `iter_enabled` function.
fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) {
fmtln!(fmt, "impl Flags {");
fmt.indent(|fmt| {
fmt.doc_comment("Iterates the enabled boolean settings.");
fmtln!(fmt, "pub fn iter_enabled(&self) -> impl Iterator<Item = &'static str> {");
fmt.indent(|fmt| {
fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size);
fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size);
fmtln!(fmt, "DESCRIPTORS.iter().filter_map(move |d| {");
fmt.indent(|fmt| {
fmtln!(fmt, "if match d.detail {");
fmt.indent(|fmt| {
fmtln!(fmt, "detail::Detail::Bool { bit } => (bytes[d.offset as usize] & (1 << bit as usize)) != 0,");
fmtln!(fmt, "_ => false");
});
fmtln!(fmt, "} {");
fmt.indent(|fmt| {
fmtln!(fmt, "Some(d.name)");
});
fmtln!(fmt, "} else {");
fmt.indent(|fmt| {
fmtln!(fmt, "None");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "})");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
}
/// Generates the `is_enabled` function.
fn gen_is_enabled(fmt: &mut Formatter) {
fmtln!(fmt, "impl Flags {");
fmt.indent(|fmt| {
fmt.doc_comment("Checks if a boolean setting is enabled by name.");
fmtln!(fmt, "pub fn is_enabled(&self, name: &str) -> bool {");
fmt.indent(|fmt| {
fmtln!(fmt, "match crate::constant_hash::probe(&TEMPLATE, name, crate::constant_hash::simple_hash(name)) {");
fmt.indent(|fmt| {
fmtln!(fmt, "Err(_) => false,");
fmtln!(fmt, "Ok(entry) => {");
fmt.indent(|fmt| {
fmtln!(fmt, "let d = &TEMPLATE.descriptors[TEMPLATE.hash_table[entry] as usize];");
fmtln!(fmt, "match &d.detail {");
fmt.indent(|fmt| {
fmtln!(fmt, "detail::Detail::Bool{ bit } => {");
fmt.indent(|fmt| {
fmtln!(fmt, "(self.bytes[d.offset as usize] & (1 << bit)) != 0");
});
fmtln!(fmt, "},");
fmtln!(fmt, "_ => false");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
}
/// Emit Display and FromStr implementations for enum settings.
fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {
fmtln!(fmt, "impl fmt::Display for {} {{", name);
@@ -427,6 +493,8 @@ fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
fmtln!(fmt, "}");
gen_constructor(group, parent, fmt);
gen_iterator(group, fmt);
gen_is_enabled(fmt);
gen_enum_types(group, fmt);
gen_getters(group, fmt);
gen_descriptors(group, fmt);

View File

@@ -8,6 +8,9 @@ use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
// Note: Wasmtime's `compile` command exposes these settings as CLI options
// If the settings change, please update src/commands/compile.rs to match.
let mut setting = SettingGroupBuilder::new("arm64");
let has_lse = setting.add_bool("has_lse", "Large System Extensions", false);

View File

@@ -3,6 +3,9 @@ use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
pub(crate) fn define(shared: &SettingGroup) -> SettingGroup {
let mut settings = SettingGroupBuilder::new("x86");
// Note: Wasmtime's `compile` command exposes these settings as CLI options
// If the settings change, please update src/commands/compile.rs to match.
// CPUID.01H:ECX
let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
@@ -85,7 +88,7 @@ pub(crate) fn define(shared: &SettingGroup) -> SettingGroup {
settings.add_predicate("use_lzcnt", predicate!(has_lzcnt));
// Some shared boolean values are used in x86 instruction predicates, so we need to group them
// in the same TargetIsa, for compabitibity with code generated by meta-python.
// in the same TargetIsa, for compatibility with code generated by meta-python.
// TODO Once all the meta generation code has been migrated from Python to Rust, we can put it
// back in the shared SettingGroup, and use it in x86 instruction predicates.