wasmtime_test_util/
wast.rs

1use anyhow::{Context, Result};
2use serde::de::DeserializeOwned;
3use serde_derive::Deserialize;
4use std::fmt;
5use std::fs;
6use std::path::Path;
7use std::path::PathBuf;
8
9/// Limits for running wast tests.
10///
11/// This is useful for sharing between `tests/wast.rs` and fuzzing, for
12/// example, and is used as the minimum threshold for configuration when
13/// fuzzing.
14///
15/// Note that it's ok to increase these numbers if a test comes along and needs
16/// it, they're just here as empirically found minimum thresholds so far and
17/// they're not too scientific.
18pub mod limits {
19    pub const MEMORY_SIZE: usize = 805 << 16;
20    pub const MEMORIES: u32 = 450;
21    pub const TABLES: u32 = 200;
22    pub const MEMORIES_PER_MODULE: u32 = 9;
23    pub const TABLES_PER_MODULE: u32 = 5;
24    pub const COMPONENT_INSTANCES: u32 = 50;
25    pub const CORE_INSTANCES: u32 = 900;
26    pub const TABLE_ELEMENTS: usize = 1000;
27    pub const CORE_INSTANCE_SIZE: usize = 64 * 1024;
28    pub const TOTAL_STACKS: u32 = 10;
29}
30
31/// Local all `*.wast` tests under `root` which should be the path to the root
32/// of the wasmtime repository.
33pub fn find_tests(root: &Path) -> Result<Vec<WastTest>> {
34    let mut tests = Vec::new();
35
36    let spec_tests = root.join("tests/spec_testsuite");
37    add_tests(
38        &mut tests,
39        &spec_tests,
40        &FindConfig::Infer(spec_test_config),
41    )
42    .with_context(|| format!("failed to add tests from `{}`", spec_tests.display()))?;
43
44    let misc_tests = root.join("tests/misc_testsuite");
45    add_tests(&mut tests, &misc_tests, &FindConfig::InTest)
46        .with_context(|| format!("failed to add tests from `{}`", misc_tests.display()))?;
47
48    let cm_tests = root.join("tests/component-model/test");
49    add_tests(
50        &mut tests,
51        &cm_tests,
52        &FindConfig::Infer(component_test_config),
53    )
54    .with_context(|| format!("failed to add tests from `{}`", cm_tests.display()))?;
55    Ok(tests)
56}
57
58enum FindConfig {
59    InTest,
60    Infer(fn(&Path) -> TestConfig),
61}
62
63fn add_tests(tests: &mut Vec<WastTest>, path: &Path, config: &FindConfig) -> Result<()> {
64    for entry in path.read_dir().context("failed to read directory")? {
65        let entry = entry.context("failed to read directory entry")?;
66        let path = entry.path();
67        if entry
68            .file_type()
69            .context("failed to get file type")?
70            .is_dir()
71        {
72            add_tests(tests, &path, config).context("failed to read sub-directory")?;
73            continue;
74        }
75
76        if path.extension().and_then(|s| s.to_str()) != Some("wast") {
77            continue;
78        }
79
80        let contents =
81            fs::read_to_string(&path).with_context(|| format!("failed to read test: {path:?}"))?;
82        let config = match config {
83            FindConfig::InTest => parse_test_config(&contents, ";;!")
84                .with_context(|| format!("failed to parse test configuration: {path:?}"))?,
85            FindConfig::Infer(f) => f(&path),
86        };
87        tests.push(WastTest {
88            path,
89            contents,
90            config,
91        })
92    }
93    Ok(())
94}
95
96fn spec_test_config(test: &Path) -> TestConfig {
97    let mut ret = TestConfig::default();
98    ret.spec_test = Some(true);
99    match spec_proposal_from_path(test) {
100        Some("wide-arithmetic") => {
101            ret.wide_arithmetic = Some(true);
102        }
103        Some("threads") => {
104            ret.threads = Some(true);
105            ret.reference_types = Some(false);
106        }
107        Some("relaxed-simd") => {
108            ret.relaxed_simd = Some(true);
109        }
110        Some("custom-page-sizes") => {
111            ret.custom_page_sizes = Some(true);
112            ret.multi_memory = Some(true);
113            ret.memory64 = Some(true);
114
115            // See commentary below in `wasm-3.0` case for why these "hog
116            // memory"
117            if test.ends_with("memory_max.wast") || test.ends_with("memory_max_i64.wast") {
118                ret.hogs_memory = Some(true);
119            }
120        }
121        Some("annotations") => {
122            ret.simd = Some(true);
123        }
124        Some("wasm-3.0") => {
125            ret.simd = Some(true);
126            ret.relaxed_simd = Some(true);
127            ret.multi_memory = Some(true);
128            ret.gc = Some(true);
129            ret.reference_types = Some(true);
130            ret.memory64 = Some(true);
131            ret.tail_call = Some(true);
132            ret.extended_const = Some(true);
133            ret.exceptions = Some(true);
134
135            if test.parent().unwrap().ends_with("legacy") {
136                ret.legacy_exceptions = Some(true);
137            }
138
139            // These tests technically don't actually hog any memory but they
140            // do have a module definition with a table/memory that is the
141            // maximum size. These modules fail to compile in the pooling
142            // allocator which has limits on the minimum size of
143            // memories/tables by default.
144            //
145            // Pretend that these hog memory to avoid running the tests in the
146            // pooling allocator.
147            if test.ends_with("memory.wast")
148                || test.ends_with("table.wast")
149                || test.ends_with("memory64.wast")
150            {
151                ret.hogs_memory = Some(true);
152            }
153        }
154        Some(proposal) => panic!("unsupported proposal {proposal:?}"),
155        None => {
156            ret.reference_types = Some(true);
157            ret.simd = Some(true);
158        }
159    }
160
161    ret
162}
163
164fn component_test_config(test: &Path) -> TestConfig {
165    let mut ret = TestConfig::default();
166    ret.spec_test = Some(true);
167    ret.reference_types = Some(true);
168    ret.multi_memory = Some(true);
169
170    if let Some(parent) = test.parent() {
171        if parent.ends_with("async") {
172            ret.component_model_async = Some(true);
173            ret.component_model_async_builtins = Some(true);
174        }
175    }
176
177    ret
178}
179
180/// Parse test configuration from the specified test, comments starting with
181/// `;;!`.
182pub fn parse_test_config<T>(wat: &str, comment: &'static str) -> Result<T>
183where
184    T: DeserializeOwned,
185{
186    // The test config source is the leading lines of the WAT file that are
187    // prefixed with `;;!`.
188    let config_lines: Vec<_> = wat
189        .lines()
190        .take_while(|l| l.starts_with(comment))
191        .map(|l| &l[comment.len()..])
192        .collect();
193    let config_text = config_lines.join("\n");
194
195    toml::from_str(&config_text).context("failed to parse the test configuration")
196}
197
198/// A `*.wast` test with its path, contents, and configuration.
199#[derive(Clone)]
200pub struct WastTest {
201    pub path: PathBuf,
202    pub contents: String,
203    pub config: TestConfig,
204}
205
206impl fmt::Debug for WastTest {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        f.debug_struct("WastTest")
209            .field("path", &self.path)
210            .field("contents", &"...")
211            .field("config", &self.config)
212            .finish()
213    }
214}
215
216macro_rules! foreach_config_option {
217    ($m:ident) => {
218        $m! {
219            memory64
220            custom_page_sizes
221            multi_memory
222            threads
223            shared_everything_threads
224            gc
225            function_references
226            relaxed_simd
227            reference_types
228            tail_call
229            extended_const
230            wide_arithmetic
231            hogs_memory
232            nan_canonicalization
233            component_model_async
234            component_model_async_builtins
235            component_model_async_stackful
236            component_model_error_context
237            component_model_gc
238            simd
239            gc_types
240            exceptions
241            legacy_exceptions
242            stack_switching
243            spec_test
244        }
245    };
246}
247
248macro_rules! define_test_config {
249    ($($option:ident)*) => {
250        /// Per-test configuration which is written down in the test file itself for
251        /// `misc_testsuite/**/*.wast` or in `spec_test_config` above for spec tests.
252        #[derive(Debug, PartialEq, Default, Deserialize, Clone)]
253        #[serde(deny_unknown_fields)]
254        pub struct TestConfig {
255            $(pub $option: Option<bool>,)*
256        }
257
258        impl TestConfig {
259            $(
260                pub fn $option(&self) -> bool {
261                    self.$option.unwrap_or(false)
262                }
263            )*
264        }
265    }
266}
267
268foreach_config_option!(define_test_config);
269
270impl TestConfig {
271    /// Returns an iterator over each option.
272    pub fn options_mut(&mut self) -> impl Iterator<Item = (&'static str, &mut Option<bool>)> {
273        macro_rules! mk {
274            ($($option:ident)*) => {
275                [
276                    $((stringify!($option), &mut self.$option),)*
277                ].into_iter()
278            }
279        }
280        foreach_config_option!(mk)
281    }
282}
283
284/// Configuration that spec tests can run under.
285#[derive(Debug)]
286pub struct WastConfig {
287    /// Compiler chosen to run this test.
288    pub compiler: Compiler,
289    /// Whether or not the pooling allocator is enabled.
290    pub pooling: bool,
291    /// What garbage collector is being used.
292    pub collector: Collector,
293}
294
295/// Different compilers that can be tested in Wasmtime.
296#[derive(PartialEq, Debug, Copy, Clone)]
297pub enum Compiler {
298    /// Cranelift backend.
299    ///
300    /// This tests the Cranelift code generator for native platforms. This
301    /// notably excludes Pulley since that's listed separately below even though
302    /// Pulley is a backend of Cranelift. This is only used for native code
303    /// generation such as x86_64.
304    CraneliftNative,
305
306    /// Winch backend.
307    ///
308    /// This tests the Winch backend for native platforms. Currently Winch
309    /// primarily supports x86_64.
310    Winch,
311
312    /// Pulley interpreter.
313    ///
314    /// This tests the Cranelift pulley backend plus the pulley execution
315    /// environment of the output bytecode. Note that this is separate from
316    /// `Cranelift` above to be able to test both on platforms where Cranelift
317    /// has native codegen support.
318    CraneliftPulley,
319}
320
321impl Compiler {
322    /// Returns whether this compiler is known to fail for the provided
323    /// `TestConfig`.
324    ///
325    /// This function will determine if the configuration of the test provided
326    /// is known to guarantee fail. This effectively tracks the proposal support
327    /// for each compiler backend/runtime and tests whether `config` enables or
328    /// disables features that aren't supported.
329    ///
330    /// Note that this is closely aligned with
331    /// `Config::compiler_panicking_wasm_features`.
332    pub fn should_fail(&self, config: &TestConfig) -> bool {
333        match self {
334            Compiler::CraneliftNative => config.legacy_exceptions(),
335
336            Compiler::Winch => {
337                if config.gc()
338                    || config.tail_call()
339                    || config.function_references()
340                    || config.gc()
341                    || config.relaxed_simd()
342                    || config.gc_types()
343                    || config.exceptions()
344                    || config.legacy_exceptions()
345                    || config.stack_switching()
346                    || config.legacy_exceptions()
347                    || config.component_model_async()
348                {
349                    return true;
350                }
351
352                if cfg!(target_arch = "aarch64") {
353                    return config.wide_arithmetic()
354                        || (config.simd() && !config.spec_test())
355                        || config.threads();
356                }
357
358                !cfg!(target_arch = "x86_64")
359            }
360
361            Compiler::CraneliftPulley => {
362                config.threads() || config.legacy_exceptions() || config.stack_switching()
363            }
364        }
365    }
366
367    /// Returns whether this compiler configuration supports the current host
368    /// architecture.
369    pub fn supports_host(&self) -> bool {
370        match self {
371            Compiler::CraneliftNative => {
372                cfg!(target_arch = "x86_64")
373                    || cfg!(target_arch = "aarch64")
374                    || cfg!(target_arch = "riscv64")
375                    || cfg!(target_arch = "s390x")
376            }
377            Compiler::Winch => cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64"),
378            Compiler::CraneliftPulley => true,
379        }
380    }
381}
382
383#[derive(PartialEq, Debug, Copy, Clone)]
384pub enum Collector {
385    Auto,
386    Null,
387    DeferredReferenceCounting,
388}
389
390impl WastTest {
391    /// Returns whether this test exercises the GC types and might want to use
392    /// multiple different garbage collectors.
393    pub fn test_uses_gc_types(&self) -> bool {
394        self.config.gc() || self.config.function_references()
395    }
396
397    /// Returns the optional spec proposal that this test is associated with.
398    pub fn spec_proposal(&self) -> Option<&str> {
399        spec_proposal_from_path(&self.path)
400    }
401
402    /// Returns whether this test should fail under the specified extra
403    /// configuration.
404    pub fn should_fail(&self, config: &WastConfig) -> bool {
405        if !config.compiler.supports_host() {
406            return true;
407        }
408
409        // Some tests are known to fail with the pooling allocator
410        if config.pooling {
411            let unsupported = [
412                // allocates too much memory for the pooling configuration here
413                "misc_testsuite/memory64/more-than-4gb.wast",
414                // shared memories + pooling allocator aren't supported yet
415                "misc_testsuite/memory-combos.wast",
416                "misc_testsuite/threads/LB.wast",
417                "misc_testsuite/threads/LB_atomic.wast",
418                "misc_testsuite/threads/MP.wast",
419                "misc_testsuite/threads/MP_atomic.wast",
420                "misc_testsuite/threads/MP_wait.wast",
421                "misc_testsuite/threads/SB.wast",
422                "misc_testsuite/threads/SB_atomic.wast",
423                "misc_testsuite/threads/atomics_notify.wast",
424                "misc_testsuite/threads/atomics_wait_address.wast",
425                "misc_testsuite/threads/wait_notify.wast",
426                "spec_testsuite/proposals/threads/atomic.wast",
427                "spec_testsuite/proposals/threads/exports.wast",
428                "spec_testsuite/proposals/threads/memory.wast",
429            ];
430
431            if unsupported.iter().any(|part| self.path.ends_with(part)) {
432                return true;
433            }
434        }
435
436        if config.compiler.should_fail(&self.config) {
437            return true;
438        }
439
440        // Disable spec tests per target for proposals that Winch does not implement yet.
441        if config.compiler == Compiler::Winch {
442            // Common list for tests that fail in all targets supported by Winch.
443            let unsupported = [
444                "extended-const/elem.wast",
445                "extended-const/global.wast",
446                "misc_testsuite/component-model/modules.wast",
447                "misc_testsuite/externref-id-function.wast",
448                "misc_testsuite/externref-segment.wast",
449                "misc_testsuite/externref-segments.wast",
450                "misc_testsuite/externref-table-dropped-segment-issue-8281.wast",
451                "misc_testsuite/linking-errors.wast",
452                "misc_testsuite/many_table_gets_lead_to_gc.wast",
453                "misc_testsuite/mutable_externref_globals.wast",
454                "misc_testsuite/no-mixup-stack-maps.wast",
455                "misc_testsuite/no-panic.wast",
456                "misc_testsuite/simple_ref_is_null.wast",
457                "misc_testsuite/table_grow_with_funcref.wast",
458                "spec_testsuite/br_table.wast",
459                "spec_testsuite/global.wast",
460                "spec_testsuite/ref_func.wast",
461                "spec_testsuite/ref_is_null.wast",
462                "spec_testsuite/ref_null.wast",
463                "spec_testsuite/select.wast",
464                "spec_testsuite/table_fill.wast",
465                "spec_testsuite/table_get.wast",
466                "spec_testsuite/table_grow.wast",
467                "spec_testsuite/table_set.wast",
468                "spec_testsuite/table_size.wast",
469                "spec_testsuite/elem.wast",
470                "spec_testsuite/linking.wast",
471            ];
472
473            if unsupported.iter().any(|part| self.path.ends_with(part)) {
474                return true;
475            }
476
477            #[cfg(target_arch = "aarch64")]
478            {
479                let unsupported = [
480                    "misc_testsuite/int-to-float-splat.wast",
481                    "misc_testsuite/issue6562.wast",
482                    "misc_testsuite/memory64/simd.wast",
483                    "misc_testsuite/simd/almost-extmul.wast",
484                    "misc_testsuite/simd/canonicalize-nan.wast",
485                    "misc_testsuite/simd/cvt-from-uint.wast",
486                    "misc_testsuite/simd/edge-of-memory.wast",
487                    "misc_testsuite/simd/interesting-float-splat.wast",
488                    "misc_testsuite/simd/issue4807.wast",
489                    "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
490                    "misc_testsuite/simd/issue_3173_select_v128.wast",
491                    "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
492                    "misc_testsuite/simd/load_splat_out_of_bounds.wast",
493                    "misc_testsuite/simd/replace-lane-preserve.wast",
494                    "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
495                    "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
496                    "misc_testsuite/simd/unaligned-load.wast",
497                    "misc_testsuite/simd/v128-select.wast",
498                    "misc_testsuite/winch/issue-10331.wast",
499                    "misc_testsuite/winch/issue-10357.wast",
500                    "misc_testsuite/winch/issue-10460.wast",
501                    "misc_testsuite/winch/replace_lane.wast",
502                    "misc_testsuite/winch/simd_multivalue.wast",
503                    "misc_testsuite/winch/v128_load_lane_invalid_address.wast",
504                    "spec_testsuite/proposals/annotations/simd_lane.wast",
505                    "spec_testsuite/proposals/multi-memory/simd_memory-multi.wast",
506                    "spec_testsuite/simd_address.wast",
507                    "spec_testsuite/simd_align.wast",
508                    "spec_testsuite/simd_bit_shift.wast",
509                    "spec_testsuite/simd_bitwise.wast",
510                    "spec_testsuite/simd_boolean.wast",
511                    "spec_testsuite/simd_const.wast",
512                    "spec_testsuite/simd_conversions.wast",
513                    "spec_testsuite/simd_f32x4.wast",
514                    "spec_testsuite/simd_f32x4_arith.wast",
515                    "spec_testsuite/simd_f32x4_cmp.wast",
516                    "spec_testsuite/simd_f32x4_pmin_pmax.wast",
517                    "spec_testsuite/simd_f32x4_rounding.wast",
518                    "spec_testsuite/simd_f64x2.wast",
519                    "spec_testsuite/simd_f64x2_arith.wast",
520                    "spec_testsuite/simd_f64x2_cmp.wast",
521                    "spec_testsuite/simd_f64x2_pmin_pmax.wast",
522                    "spec_testsuite/simd_f64x2_rounding.wast",
523                    "spec_testsuite/simd_i16x8_arith.wast",
524                    "spec_testsuite/simd_i16x8_arith2.wast",
525                    "spec_testsuite/simd_i16x8_cmp.wast",
526                    "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
527                    "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
528                    "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
529                    "spec_testsuite/simd_i16x8_sat_arith.wast",
530                    "spec_testsuite/simd_i32x4_arith.wast",
531                    "spec_testsuite/simd_i32x4_arith2.wast",
532                    "spec_testsuite/simd_i32x4_cmp.wast",
533                    "spec_testsuite/simd_i32x4_dot_i16x8.wast",
534                    "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
535                    "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
536                    "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
537                    "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
538                    "spec_testsuite/simd_i64x2_arith.wast",
539                    "spec_testsuite/simd_i64x2_arith2.wast",
540                    "spec_testsuite/simd_i64x2_cmp.wast",
541                    "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
542                    "spec_testsuite/simd_i8x16_arith.wast",
543                    "spec_testsuite/simd_i8x16_arith2.wast",
544                    "spec_testsuite/simd_i8x16_cmp.wast",
545                    "spec_testsuite/simd_i8x16_sat_arith.wast",
546                    "spec_testsuite/simd_int_to_int_extend.wast",
547                    "spec_testsuite/simd_lane.wast",
548                    "spec_testsuite/simd_load.wast",
549                    "spec_testsuite/simd_load16_lane.wast",
550                    "spec_testsuite/simd_load32_lane.wast",
551                    "spec_testsuite/simd_load64_lane.wast",
552                    "spec_testsuite/simd_load8_lane.wast",
553                    "spec_testsuite/simd_load_extend.wast",
554                    "spec_testsuite/simd_load_splat.wast",
555                    "spec_testsuite/simd_load_zero.wast",
556                    "spec_testsuite/simd_select.wast",
557                    "spec_testsuite/simd_splat.wast",
558                    "spec_testsuite/simd_store.wast",
559                    "spec_testsuite/simd_store16_lane.wast",
560                    "spec_testsuite/simd_store32_lane.wast",
561                    "spec_testsuite/simd_store64_lane.wast",
562                    "spec_testsuite/simd_store8_lane.wast",
563                ];
564
565                if unsupported.iter().any(|part| self.path.ends_with(part)) {
566                    return true;
567                }
568            }
569
570            #[cfg(target_arch = "x86_64")]
571            {
572                let unsupported = [
573                    // externref/reference-types related
574                    // simd-related failures
575                    "misc_testsuite/simd/canonicalize-nan.wast",
576                ];
577
578                if unsupported.iter().any(|part| self.path.ends_with(part)) {
579                    return true;
580                }
581
582                // SIMD on Winch requires AVX instructions.
583                #[cfg(target_arch = "x86_64")]
584                if !(std::is_x86_feature_detected!("avx") && std::is_x86_feature_detected!("avx2"))
585                {
586                    let unsupported = [
587                        "annotations/simd_lane.wast",
588                        "memory64/simd.wast",
589                        "misc_testsuite/int-to-float-splat.wast",
590                        "misc_testsuite/issue6562.wast",
591                        "misc_testsuite/simd/almost-extmul.wast",
592                        "misc_testsuite/simd/cvt-from-uint.wast",
593                        "misc_testsuite/simd/edge-of-memory.wast",
594                        "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
595                        "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
596                        "misc_testsuite/simd/replace-lane-preserve.wast",
597                        "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
598                        "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
599                        "misc_testsuite/winch/issue-10331.wast",
600                        "misc_testsuite/winch/replace_lane.wast",
601                        "spec_testsuite/simd_align.wast",
602                        "spec_testsuite/simd_boolean.wast",
603                        "spec_testsuite/simd_conversions.wast",
604                        "spec_testsuite/simd_f32x4.wast",
605                        "spec_testsuite/simd_f32x4_arith.wast",
606                        "spec_testsuite/simd_f32x4_cmp.wast",
607                        "spec_testsuite/simd_f32x4_pmin_pmax.wast",
608                        "spec_testsuite/simd_f32x4_rounding.wast",
609                        "spec_testsuite/simd_f64x2.wast",
610                        "spec_testsuite/simd_f64x2_arith.wast",
611                        "spec_testsuite/simd_f64x2_cmp.wast",
612                        "spec_testsuite/simd_f64x2_pmin_pmax.wast",
613                        "spec_testsuite/simd_f64x2_rounding.wast",
614                        "spec_testsuite/simd_i16x8_cmp.wast",
615                        "spec_testsuite/simd_i32x4_cmp.wast",
616                        "spec_testsuite/simd_i64x2_arith2.wast",
617                        "spec_testsuite/simd_i64x2_cmp.wast",
618                        "spec_testsuite/simd_i8x16_arith2.wast",
619                        "spec_testsuite/simd_i8x16_cmp.wast",
620                        "spec_testsuite/simd_int_to_int_extend.wast",
621                        "spec_testsuite/simd_load.wast",
622                        "spec_testsuite/simd_load_extend.wast",
623                        "spec_testsuite/simd_load_splat.wast",
624                        "spec_testsuite/simd_load_zero.wast",
625                        "spec_testsuite/simd_splat.wast",
626                        "spec_testsuite/simd_store16_lane.wast",
627                        "spec_testsuite/simd_store32_lane.wast",
628                        "spec_testsuite/simd_store64_lane.wast",
629                        "spec_testsuite/simd_store8_lane.wast",
630                        "spec_testsuite/simd_load16_lane.wast",
631                        "spec_testsuite/simd_load32_lane.wast",
632                        "spec_testsuite/simd_load64_lane.wast",
633                        "spec_testsuite/simd_load8_lane.wast",
634                        "spec_testsuite/simd_bitwise.wast",
635                        "misc_testsuite/simd/load_splat_out_of_bounds.wast",
636                        "misc_testsuite/simd/unaligned-load.wast",
637                        "multi-memory/simd_memory-multi.wast",
638                        "misc_testsuite/simd/issue4807.wast",
639                        "spec_testsuite/simd_const.wast",
640                        "spec_testsuite/simd_i8x16_sat_arith.wast",
641                        "spec_testsuite/simd_i64x2_arith.wast",
642                        "spec_testsuite/simd_i16x8_arith.wast",
643                        "spec_testsuite/simd_i16x8_arith2.wast",
644                        "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
645                        "spec_testsuite/simd_i16x8_sat_arith.wast",
646                        "spec_testsuite/simd_i32x4_arith.wast",
647                        "spec_testsuite/simd_i32x4_dot_i16x8.wast",
648                        "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
649                        "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
650                        "spec_testsuite/simd_i8x16_arith.wast",
651                        "spec_testsuite/simd_bit_shift.wast",
652                        "spec_testsuite/simd_lane.wast",
653                        "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
654                        "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
655                        "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
656                        "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
657                        "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
658                        "spec_testsuite/simd_i32x4_arith2.wast",
659                    ];
660
661                    if unsupported.iter().any(|part| self.path.ends_with(part)) {
662                        return true;
663                    }
664                }
665            }
666        }
667
668        let failing_component_model_tests = [
669            // FIXME(#11683)
670            "component-model/test/values/trap-in-post-return.wast",
671        ];
672        if failing_component_model_tests
673            .iter()
674            .any(|part| self.path.ends_with(part))
675        {
676            return true;
677        }
678
679        false
680    }
681}
682
683fn spec_proposal_from_path(path: &Path) -> Option<&str> {
684    let mut iter = path.iter();
685    loop {
686        match iter.next()?.to_str()? {
687            "proposals" => break,
688            _ => {}
689        }
690    }
691    Some(iter.next()?.to_str()?)
692}