* Switch duplicate loads w/ dynamic memories test to `min_size = 0` This test was accidentally hitting a special case for bounds checks for when we know that `offset + access_size < min_size` and can skip some steps. This commit changes the `min_size` of the memory to zero so that we are forced to do fully general bounds checks. * Cranelift: Mark `uadd_overflow_trap` as okay for GVN Although this improves our test sequence for duplicate loads with dynamic memories, it unfortunately doesn't have any effect on sightglass benchmarks: ``` instantiation :: instructions-retired :: benchmarks/pulldown-cmark/benchmark.wasm No difference in performance. [34448 35607.23 37158] gvn_uadd_overflow_trap.so [34566 35734.05 36585] main.so instantiation :: instructions-retired :: benchmarks/spidermonkey/benchmark.wasm No difference in performance. [44101 60449.62 92712] gvn_uadd_overflow_trap.so [44011 60436.37 92690] main.so instantiation :: instructions-retired :: benchmarks/bz2/benchmark.wasm No difference in performance. [35595 36675.72 38153] gvn_uadd_overflow_trap.so [35440 36670.42 37993] main.so compilation :: instructions-retired :: benchmarks/bz2/benchmark.wasm No difference in performance. [17370195 17405125.62 17471222] gvn_uadd_overflow_trap.so [17369324 17404859.43 17470725] main.so execution :: instructions-retired :: benchmarks/spidermonkey/benchmark.wasm No difference in performance. [7055720520 7055886880.32 7056265930] gvn_uadd_overflow_trap.so [7055719554 7055843809.33 7056193289] main.so compilation :: instructions-retired :: benchmarks/spidermonkey/benchmark.wasm No difference in performance. [683589861 683767276.00 684098366] gvn_uadd_overflow_trap.so [683590024 683767998.02 684097885] main.so execution :: instructions-retired :: benchmarks/pulldown-cmark/benchmark.wasm No difference in performance. [46436883 46437135.10 46437823] gvn_uadd_overflow_trap.so [46436883 46437087.67 46437785] main.so compilation :: instructions-retired :: benchmarks/pulldown-cmark/benchmark.wasm No difference in performance. [126522461 126565812.58 126647044] gvn_uadd_overflow_trap.so [126522176 126565757.75 126647522] main.so execution :: instructions-retired :: benchmarks/bz2/benchmark.wasm No difference in performance. [653010531 653010533.03 653010544] gvn_uadd_overflow_trap.so [653010531 653010533.18 653010537] main.so ``` * cranelift-codegen-meta: Rename `side_effects_okay_for_gvn` to `side_effects_idempotent` * cranelift-filetests: Ensure there is a trailing newline for blessed Wasm tests
134 lines
4.4 KiB
Rust
134 lines
4.4 KiB
Rust
//! Test runner for `.wat` files to exercise CLIF-to-Wasm translations.
|
|
|
|
mod config;
|
|
mod env;
|
|
|
|
use anyhow::{bail, ensure, Context, Result};
|
|
use config::TestConfig;
|
|
use env::ModuleEnv;
|
|
use similar::TextDiff;
|
|
use std::{fmt::Write, path::Path};
|
|
|
|
/// Run one `.wat` test.
|
|
pub fn run(path: &Path, wat: &str) -> Result<()> {
|
|
debug_assert_eq!(path.extension().unwrap_or_default(), "wat");
|
|
|
|
// The test config source is the leading lines of the WAT file that are
|
|
// prefixed with `;;!`.
|
|
let config_lines: Vec<_> = wat
|
|
.lines()
|
|
.take_while(|l| l.starts_with(";;!"))
|
|
.map(|l| &l[3..])
|
|
.collect();
|
|
let config_text = config_lines.join("\n");
|
|
|
|
let config: TestConfig =
|
|
toml::from_str(&config_text).context("failed to parse the test configuration")?;
|
|
|
|
config
|
|
.validate()
|
|
.context("test configuration is malformed")?;
|
|
|
|
let parsed = cranelift_reader::parse_sets_and_triple(&config.settings, &config.target)
|
|
.context("invalid ISA target or Cranelift settings")?;
|
|
let flags_or_isa = parsed.as_fisa();
|
|
ensure!(
|
|
flags_or_isa.isa.is_some(),
|
|
"Running `.wat` tests requires specifying an ISA"
|
|
);
|
|
let isa = flags_or_isa.isa.unwrap();
|
|
|
|
let mut env = ModuleEnv::new(isa, config.clone());
|
|
|
|
let wasm = wat::parse_str(wat).context("failed to parse the test WAT")?;
|
|
let mut validator = wasmparser::Validator::new_with_features(
|
|
cranelift_wasm::ModuleEnvironment::wasm_features(&env),
|
|
);
|
|
validator
|
|
.validate_all(&wasm)
|
|
.context("test WAT failed to validate")?;
|
|
|
|
cranelift_wasm::translate_module(&wasm, &mut env)
|
|
.context("failed to translate the test case into CLIF")?;
|
|
|
|
let mut actual = String::new();
|
|
for (_index, func) in env.inner.info.function_bodies.iter() {
|
|
if config.compile {
|
|
let mut ctx = cranelift_codegen::Context::for_function(func.clone());
|
|
ctx.set_disasm(true);
|
|
let code = ctx
|
|
.compile(isa)
|
|
.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?;
|
|
writeln!(&mut actual, "function {}:", func.name).unwrap();
|
|
writeln!(&mut actual, "{}", code.disasm.as_ref().unwrap()).unwrap();
|
|
} else if config.optimize {
|
|
let mut ctx = cranelift_codegen::Context::for_function(func.clone());
|
|
ctx.optimize(isa)
|
|
.map_err(|e| crate::pretty_anyhow_error(&ctx.func, e))?;
|
|
writeln!(&mut actual, "{}", ctx.func.display()).unwrap();
|
|
} else {
|
|
writeln!(&mut actual, "{}", func.display()).unwrap();
|
|
}
|
|
}
|
|
let actual = actual.trim();
|
|
log::debug!("=== actual ===\n{actual}");
|
|
|
|
// The test's expectation is the final comment.
|
|
let mut expected_lines: Vec<_> = wat
|
|
.lines()
|
|
.rev()
|
|
.take_while(|l| l.starts_with(";;"))
|
|
.map(|l| {
|
|
if l.starts_with(";; ") {
|
|
&l[3..]
|
|
} else {
|
|
&l[2..]
|
|
}
|
|
})
|
|
.collect();
|
|
expected_lines.reverse();
|
|
let expected = expected_lines.join("\n");
|
|
let expected = expected.trim();
|
|
log::debug!("=== expected ===\n{expected}");
|
|
|
|
if actual == expected {
|
|
return Ok(());
|
|
}
|
|
|
|
if std::env::var("CRANELIFT_TEST_BLESS").unwrap_or_default() == "1" {
|
|
let old_expectation_line_count = wat
|
|
.lines()
|
|
.rev()
|
|
.take_while(|l| l.starts_with(";;"))
|
|
.count();
|
|
let old_wat_line_count = wat.lines().count();
|
|
let new_wat_lines: Vec<_> = wat
|
|
.lines()
|
|
.take(old_wat_line_count - old_expectation_line_count)
|
|
.map(|l| l.to_string())
|
|
.chain(actual.lines().map(|l| {
|
|
if l.is_empty() {
|
|
";;".to_string()
|
|
} else {
|
|
format!(";; {l}")
|
|
}
|
|
}))
|
|
.collect();
|
|
let mut new_wat = new_wat_lines.join("\n");
|
|
new_wat.push('\n');
|
|
std::fs::write(path, new_wat)
|
|
.with_context(|| format!("failed to write file: {}", path.display()))?;
|
|
return Ok(());
|
|
}
|
|
|
|
bail!(
|
|
"Did not get the expected CLIF translation:\n\n\
|
|
{}\n\n\
|
|
Note: You can re-run with the `CRANELIFT_TEST_BLESS=1` environment\n\
|
|
variable set to update test expectations.",
|
|
TextDiff::from_lines(expected, actual)
|
|
.unified_diff()
|
|
.header("expected", "actual")
|
|
)
|
|
}
|