cranelift-filetest: Add support for Wasm-to-CLIF translation filetests (#5412)
This adds support for `.wat` tests in `cranelift-filetest`. The test runner translates the WAT to Wasm and then uses `cranelift-wasm` to translate the Wasm to CLIF. These tests are always precise output tests. The test expectations can be updated by running tests with the `CRANELIFT_TEST_BLESS=1` environment variable set, similar to our compile precise output tests. The test's expected output is contained in the last comment in the test file. The tests allow for configuring the kinds of heaps used to implement Wasm linear memory via TOML in a `;;!` comment at the start of the test. To get ISA and Cranelift flags parsing available in the filetests crate, I had to move the `parse_sets_and_triple` helper from the `cranelift-tools` binary crate to the `cranelift-reader` crate, where I think it logically fits. Additionally, I had to make some more bits of `cranelift-wasm`'s dummy environment `pub` so that I could properly wrap and compose it with the environment used for the `.wat` tests. I don't think this is a big deal, but if we eventually want to clean this stuff up, we can probably remove the dummy environments completely, remove `translate_module`, and fold them into these new test environments and test runner (since Wasmtime isn't using those things anyways).
This commit is contained in:
@@ -10,6 +10,7 @@ readme = "README.md"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
cranelift-codegen = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
target-lexicon = { workspace = true }
|
||||
|
||||
@@ -45,3 +45,89 @@ mod run_command;
|
||||
mod sourcemap;
|
||||
mod testcommand;
|
||||
mod testfile;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use cranelift_codegen::isa::{self, TargetIsa};
|
||||
use cranelift_codegen::settings::{self, FlagsOrIsa};
|
||||
use std::str::FromStr;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
/// Like `FlagsOrIsa`, but holds ownership.
|
||||
#[allow(missing_docs)]
|
||||
pub enum OwnedFlagsOrIsa {
|
||||
Flags(settings::Flags),
|
||||
Isa(Box<dyn TargetIsa>),
|
||||
}
|
||||
|
||||
impl OwnedFlagsOrIsa {
|
||||
/// Produce a FlagsOrIsa reference.
|
||||
pub fn as_fisa(&self) -> FlagsOrIsa {
|
||||
match *self {
|
||||
Self::Flags(ref flags) => FlagsOrIsa::from(flags),
|
||||
Self::Isa(ref isa) => FlagsOrIsa::from(&**isa),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse "set" and "triple" commands.
|
||||
pub fn parse_sets_and_triple(flag_set: &[String], flag_triple: &str) -> Result<OwnedFlagsOrIsa> {
|
||||
let mut flag_builder = settings::builder();
|
||||
|
||||
// Collect unknown system-wide settings, so we can try to parse them as target specific
|
||||
// settings, if a target is defined.
|
||||
let mut unknown_settings = Vec::new();
|
||||
match parse_options(
|
||||
flag_set.iter().map(|x| x.as_str()),
|
||||
&mut flag_builder,
|
||||
Location { line_number: 0 },
|
||||
) {
|
||||
Err(ParseOptionError::UnknownFlag { name, .. }) => {
|
||||
unknown_settings.push(name);
|
||||
}
|
||||
Err(ParseOptionError::UnknownValue { name, value, .. }) => {
|
||||
unknown_settings.push(format!("{}={}", name, value));
|
||||
}
|
||||
Err(ParseOptionError::Generic(err)) => return Err(err.into()),
|
||||
Ok(()) => {}
|
||||
}
|
||||
|
||||
let mut words = flag_triple.trim().split_whitespace();
|
||||
// Look for `target foo`.
|
||||
if let Some(triple_name) = words.next() {
|
||||
let triple = match Triple::from_str(triple_name) {
|
||||
Ok(triple) => triple,
|
||||
Err(parse_error) => return Err(Error::from(parse_error)),
|
||||
};
|
||||
|
||||
let mut isa_builder = isa::lookup(triple).map_err(|err| match err {
|
||||
isa::LookupError::SupportDisabled => {
|
||||
anyhow::anyhow!("support for triple '{}' is disabled", triple_name)
|
||||
}
|
||||
isa::LookupError::Unsupported => anyhow::anyhow!(
|
||||
"support for triple '{}' is not implemented yet",
|
||||
triple_name
|
||||
),
|
||||
})?;
|
||||
|
||||
// Try to parse system-wide unknown settings as target-specific settings.
|
||||
parse_options(
|
||||
unknown_settings.iter().map(|x| x.as_str()),
|
||||
&mut isa_builder,
|
||||
Location { line_number: 0 },
|
||||
)
|
||||
.map_err(ParseError::from)?;
|
||||
|
||||
// Apply the ISA-specific settings to `isa_builder`.
|
||||
parse_options(words, &mut isa_builder, Location { line_number: 0 })
|
||||
.map_err(ParseError::from)?;
|
||||
|
||||
Ok(OwnedFlagsOrIsa::Isa(
|
||||
isa_builder.finish(settings::Flags::new(flag_builder))?,
|
||||
))
|
||||
} else {
|
||||
if !unknown_settings.is_empty() {
|
||||
anyhow::bail!("unknown settings: '{}'", unknown_settings.join("', '"));
|
||||
}
|
||||
Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(flag_builder)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user