diff --git a/Cargo.toml b/Cargo.toml index 5665df9686..6ec1471b63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,7 @@ wasm-metadata = { version = "0.220.0", path = "crates/wasm-metadata" } wasm-mutate = { version = "0.220.0", path = "crates/wasm-mutate" } wasm-shrink = { version = "0.220.0", path = "crates/wasm-shrink" } wasm-smith = { version = "0.220.0", path = "crates/wasm-smith" } -wasmparser = { version = "0.220.0", path = "crates/wasmparser", default-features = false, features = ['std'] } +wasmparser = { version = "0.220.0", path = "crates/wasmparser", default-features = false, features = ['std','simd'] } wasmprinter = { version = "0.220.0", path = "crates/wasmprinter", default-features = false } wast = { version = "220.0.0", path = "crates/wast", default-features = false } wat = { version = "1.220.0", path = "crates/wat", default-features = false } @@ -122,7 +122,7 @@ wat = { workspace = true, features = ['dwarf', 'component-model'] } termcolor = { workspace = true } # Dependencies of `validate` -wasmparser = { workspace = true, optional = true, features = ['component-model'] } +wasmparser = { workspace = true, optional = true, features = ['component-model', 'simd'] } rayon = { workspace = true, optional = true } bitflags = { workspace = true, optional = true } diff --git a/crates/wasm-encoder/Cargo.toml b/crates/wasm-encoder/Cargo.toml index f547e9ae19..eea73ba858 100644 --- a/crates/wasm-encoder/Cargo.toml +++ b/crates/wasm-encoder/Cargo.toml @@ -24,7 +24,7 @@ leb128 = { workspace = true } # Enable this dependency to get a bunch of `From for # wasm_encoder::Foo` impls. -wasmparser = { optional = true, workspace = true } +wasmparser = { optional = true, workspace = true, features = ["simd"] } [dev-dependencies] anyhow = { workspace = true } diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index bba2f9c2bf..b85c406166 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -1563,6 +1563,7 @@ pub mod utils { translate!(build $op $($($arg)*)?) } )* + unexpected => unreachable!("encountered unexpected Wasm operator: {unexpected:?}"), }) }; diff --git a/crates/wasm-mutate/Cargo.toml b/crates/wasm-mutate/Cargo.toml index 6f763af313..17f12a4a3f 100644 --- a/crates/wasm-mutate/Cargo.toml +++ b/crates/wasm-mutate/Cargo.toml @@ -13,8 +13,8 @@ workspace = true [dependencies] clap = { workspace = true, optional = true } thiserror = "1.0.28" -wasmparser = { workspace = true } -wasm-encoder = { workspace = true, features = ["wasmparser"] } +wasmparser = { workspace = true, features = ['simd'] } +wasm-encoder = { workspace = true, features = ['wasmparser'] } rand = { workspace = true } log = { workspace = true } egg = "0.6.0" @@ -24,4 +24,4 @@ anyhow = { workspace = true } wat = { workspace = true } wasmprinter = { workspace = true } env_logger = { workspace = true } -wasmparser = { workspace = true, features = ['validate', 'features'] } +wasmparser = { workspace = true, features = ['validate', 'features', 'simd'] } diff --git a/crates/wasm-smith/Cargo.toml b/crates/wasm-smith/Cargo.toml index f7275ff381..f432ffac88 100644 --- a/crates/wasm-smith/Cargo.toml +++ b/crates/wasm-smith/Cargo.toml @@ -32,13 +32,13 @@ leb128 = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } wasm-encoder = { workspace = true } -wasmparser = { workspace = true, optional = true, features = ['validate', 'features'] } +wasmparser = { workspace = true, optional = true, features = ['validate', 'features', 'simd'] } wat = { workspace = true, optional = true } [dev-dependencies] criterion = { workspace = true } rand = { workspace = true } -wasmparser = { workspace = true, features = ["validate", "features"] } +wasmparser = { workspace = true, features = ['validate', 'features', 'simd'] } wasmprinter = { workspace = true } wat = { workspace = true } diff --git a/crates/wasmparser/Cargo.toml b/crates/wasmparser/Cargo.toml index 52753ce31e..8378daba35 100644 --- a/crates/wasmparser/Cargo.toml +++ b/crates/wasmparser/Cargo.toml @@ -42,7 +42,7 @@ name = "benchmark" harness = false [features] -default = ['std', 'validate', 'serde', 'features', 'component-model', 'hash-collections'] +default = ['std', 'validate', 'serde', 'features', 'component-model', 'hash-collections', 'simd'] # A feature which enables implementations of `std::error::Error` as appropriate # along with other convenience APIs. This additionally uses the standard @@ -82,3 +82,8 @@ features = [] # WebAssembly. This is enabled by default but if your use case is only # interested in working with core modules then this feature can be disabled. component-model = ['dep:semver'] + +# A feature that enables parsing and validating the `simd` and `relaxed-simd` +# proposals for WebAssembly. This is enabled by default but if your use case is +# only interested in working on non-SIMD code then this feature can be disabled. +simd = [] diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index e9149e189a..210de00058 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -4,6 +4,7 @@ use once_cell::unsync::Lazy; use std::fs; use std::path::Path; use std::path::PathBuf; +use wasmparser::VisitSimdOperator; use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures}; /// A benchmark input. @@ -364,5 +365,14 @@ macro_rules! define_visit_operator { impl<'a> VisitOperator<'a> for NopVisit { type Output = (); - wasmparser::for_each_operator!(define_visit_operator); + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + wasmparser::for_each_visit_operator!(define_visit_operator); +} + +#[allow(unused_variables)] +impl<'a> VisitSimdOperator<'a> for NopVisit { + wasmparser::for_each_visit_simd_operator!(define_visit_operator); } diff --git a/crates/wasmparser/src/arity.rs b/crates/wasmparser/src/arity.rs index b98d0054a8..9f60d86ced 100644 --- a/crates/wasmparser/src/arity.rs +++ b/crates/wasmparser/src/arity.rs @@ -253,6 +253,6 @@ impl Operator<'_> { } ); } - for_each_operator!(define_arity) + crate::for_each_operator!(define_arity) } } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index aab5fc33b2..d1eb395403 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -13,6 +13,9 @@ * limitations under the License. */ +#[cfg(feature = "simd")] +mod simd; + use crate::prelude::*; use crate::{limits::*, *}; use core::fmt; @@ -846,7 +849,7 @@ impl<'a> BinaryReader<'a> { /// Store an offset for use in diagnostics or any other purposes: /// /// ``` - /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_operator}; + /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_visit_operator}; /// /// pub fn dump(mut reader: BinaryReader) -> Result<()> { /// let mut visitor = Dumper { offset: 0 }; @@ -873,7 +876,7 @@ impl<'a> BinaryReader<'a> { /// /// impl<'a> VisitOperator<'a> for Dumper { /// type Output = (); - /// for_each_operator!(define_visit_operator); + /// for_each_visit_operator!(define_visit_operator); /// } /// /// ``` @@ -1120,7 +1123,13 @@ impl<'a> BinaryReader<'a> { 0xfb => self.visit_0xfb_operator(pos, visitor)?, 0xfc => self.visit_0xfc_operator(pos, visitor)?, - 0xfd => self.visit_0xfd_operator(pos, visitor)?, + 0xfd => { + #[cfg(feature = "simd")] + if let Some(mut visitor) = visitor.simd_visitor() { + return self.visit_0xfd_operator(pos, &mut visitor); + } + bail!(pos, "unexpected SIMD opcode: 0x{code:x}") + } 0xfe => self.visit_0xfe_operator(pos, visitor)?, _ => bail!(pos, "illegal opcode: 0x{code:x}"), @@ -1366,322 +1375,6 @@ impl<'a> BinaryReader<'a> { }) } - fn visit_0xfd_operator( - &mut self, - pos: usize, - visitor: &mut T, - ) -> Result<>::Output> - where - T: VisitOperator<'a>, - { - let code = self.read_var_u32()?; - Ok(match code { - 0x00 => visitor.visit_v128_load(self.read_memarg(4)?), - 0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?), - 0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?), - 0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?), - 0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?), - 0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?), - 0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?), - 0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?), - 0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?), - 0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?), - 0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?), - - 0x0b => visitor.visit_v128_store(self.read_memarg(4)?), - 0x0c => visitor.visit_v128_const(self.read_v128()?), - 0x0d => { - let mut lanes: [u8; 16] = [0; 16]; - for lane in &mut lanes { - *lane = self.read_lane_index(32)? - } - visitor.visit_i8x16_shuffle(lanes) - } - - 0x0e => visitor.visit_i8x16_swizzle(), - 0x0f => visitor.visit_i8x16_splat(), - 0x10 => visitor.visit_i16x8_splat(), - 0x11 => visitor.visit_i32x4_splat(), - 0x12 => visitor.visit_i64x2_splat(), - 0x13 => visitor.visit_f32x4_splat(), - 0x14 => visitor.visit_f64x2_splat(), - - 0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index(16)?), - 0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index(16)?), - 0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index(16)?), - 0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index(8)?), - 0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index(8)?), - 0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index(8)?), - 0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index(4)?), - - 0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index(4)?), - 0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index(2)?), - 0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index(2)?), - 0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index(4)?), - 0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index(4)?), - 0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index(2)?), - 0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index(2)?), - - 0x23 => visitor.visit_i8x16_eq(), - 0x24 => visitor.visit_i8x16_ne(), - 0x25 => visitor.visit_i8x16_lt_s(), - 0x26 => visitor.visit_i8x16_lt_u(), - 0x27 => visitor.visit_i8x16_gt_s(), - 0x28 => visitor.visit_i8x16_gt_u(), - 0x29 => visitor.visit_i8x16_le_s(), - 0x2a => visitor.visit_i8x16_le_u(), - 0x2b => visitor.visit_i8x16_ge_s(), - 0x2c => visitor.visit_i8x16_ge_u(), - 0x2d => visitor.visit_i16x8_eq(), - 0x2e => visitor.visit_i16x8_ne(), - 0x2f => visitor.visit_i16x8_lt_s(), - 0x30 => visitor.visit_i16x8_lt_u(), - 0x31 => visitor.visit_i16x8_gt_s(), - 0x32 => visitor.visit_i16x8_gt_u(), - 0x33 => visitor.visit_i16x8_le_s(), - 0x34 => visitor.visit_i16x8_le_u(), - 0x35 => visitor.visit_i16x8_ge_s(), - 0x36 => visitor.visit_i16x8_ge_u(), - 0x37 => visitor.visit_i32x4_eq(), - 0x38 => visitor.visit_i32x4_ne(), - 0x39 => visitor.visit_i32x4_lt_s(), - 0x3a => visitor.visit_i32x4_lt_u(), - 0x3b => visitor.visit_i32x4_gt_s(), - 0x3c => visitor.visit_i32x4_gt_u(), - 0x3d => visitor.visit_i32x4_le_s(), - 0x3e => visitor.visit_i32x4_le_u(), - 0x3f => visitor.visit_i32x4_ge_s(), - 0x40 => visitor.visit_i32x4_ge_u(), - 0x41 => visitor.visit_f32x4_eq(), - 0x42 => visitor.visit_f32x4_ne(), - 0x43 => visitor.visit_f32x4_lt(), - 0x44 => visitor.visit_f32x4_gt(), - 0x45 => visitor.visit_f32x4_le(), - 0x46 => visitor.visit_f32x4_ge(), - 0x47 => visitor.visit_f64x2_eq(), - 0x48 => visitor.visit_f64x2_ne(), - 0x49 => visitor.visit_f64x2_lt(), - 0x4a => visitor.visit_f64x2_gt(), - 0x4b => visitor.visit_f64x2_le(), - 0x4c => visitor.visit_f64x2_ge(), - 0x4d => visitor.visit_v128_not(), - 0x4e => visitor.visit_v128_and(), - 0x4f => visitor.visit_v128_andnot(), - 0x50 => visitor.visit_v128_or(), - 0x51 => visitor.visit_v128_xor(), - 0x52 => visitor.visit_v128_bitselect(), - 0x53 => visitor.visit_v128_any_true(), - - 0x54 => { - let memarg = self.read_memarg(0)?; - let lane = self.read_lane_index(16)?; - visitor.visit_v128_load8_lane(memarg, lane) - } - 0x55 => { - let memarg = self.read_memarg(1)?; - let lane = self.read_lane_index(8)?; - visitor.visit_v128_load16_lane(memarg, lane) - } - 0x56 => { - let memarg = self.read_memarg(2)?; - let lane = self.read_lane_index(4)?; - visitor.visit_v128_load32_lane(memarg, lane) - } - 0x57 => { - let memarg = self.read_memarg(3)?; - let lane = self.read_lane_index(2)?; - visitor.visit_v128_load64_lane(memarg, lane) - } - 0x58 => { - let memarg = self.read_memarg(0)?; - let lane = self.read_lane_index(16)?; - visitor.visit_v128_store8_lane(memarg, lane) - } - 0x59 => { - let memarg = self.read_memarg(1)?; - let lane = self.read_lane_index(8)?; - visitor.visit_v128_store16_lane(memarg, lane) - } - 0x5a => { - let memarg = self.read_memarg(2)?; - let lane = self.read_lane_index(4)?; - visitor.visit_v128_store32_lane(memarg, lane) - } - 0x5b => { - let memarg = self.read_memarg(3)?; - let lane = self.read_lane_index(2)?; - visitor.visit_v128_store64_lane(memarg, lane) - } - - 0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?), - 0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?), - 0x5e => visitor.visit_f32x4_demote_f64x2_zero(), - 0x5f => visitor.visit_f64x2_promote_low_f32x4(), - 0x60 => visitor.visit_i8x16_abs(), - 0x61 => visitor.visit_i8x16_neg(), - 0x62 => visitor.visit_i8x16_popcnt(), - 0x63 => visitor.visit_i8x16_all_true(), - 0x64 => visitor.visit_i8x16_bitmask(), - 0x65 => visitor.visit_i8x16_narrow_i16x8_s(), - 0x66 => visitor.visit_i8x16_narrow_i16x8_u(), - 0x67 => visitor.visit_f32x4_ceil(), - 0x68 => visitor.visit_f32x4_floor(), - 0x69 => visitor.visit_f32x4_trunc(), - 0x6a => visitor.visit_f32x4_nearest(), - 0x6b => visitor.visit_i8x16_shl(), - 0x6c => visitor.visit_i8x16_shr_s(), - 0x6d => visitor.visit_i8x16_shr_u(), - 0x6e => visitor.visit_i8x16_add(), - 0x6f => visitor.visit_i8x16_add_sat_s(), - 0x70 => visitor.visit_i8x16_add_sat_u(), - 0x71 => visitor.visit_i8x16_sub(), - 0x72 => visitor.visit_i8x16_sub_sat_s(), - 0x73 => visitor.visit_i8x16_sub_sat_u(), - 0x74 => visitor.visit_f64x2_ceil(), - 0x75 => visitor.visit_f64x2_floor(), - 0x76 => visitor.visit_i8x16_min_s(), - 0x77 => visitor.visit_i8x16_min_u(), - 0x78 => visitor.visit_i8x16_max_s(), - 0x79 => visitor.visit_i8x16_max_u(), - 0x7a => visitor.visit_f64x2_trunc(), - 0x7b => visitor.visit_i8x16_avgr_u(), - 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(), - 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(), - 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(), - 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(), - 0x80 => visitor.visit_i16x8_abs(), - 0x81 => visitor.visit_i16x8_neg(), - 0x82 => visitor.visit_i16x8_q15mulr_sat_s(), - 0x83 => visitor.visit_i16x8_all_true(), - 0x84 => visitor.visit_i16x8_bitmask(), - 0x85 => visitor.visit_i16x8_narrow_i32x4_s(), - 0x86 => visitor.visit_i16x8_narrow_i32x4_u(), - 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(), - 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(), - 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(), - 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(), - 0x8b => visitor.visit_i16x8_shl(), - 0x8c => visitor.visit_i16x8_shr_s(), - 0x8d => visitor.visit_i16x8_shr_u(), - 0x8e => visitor.visit_i16x8_add(), - 0x8f => visitor.visit_i16x8_add_sat_s(), - 0x90 => visitor.visit_i16x8_add_sat_u(), - 0x91 => visitor.visit_i16x8_sub(), - 0x92 => visitor.visit_i16x8_sub_sat_s(), - 0x93 => visitor.visit_i16x8_sub_sat_u(), - 0x94 => visitor.visit_f64x2_nearest(), - 0x95 => visitor.visit_i16x8_mul(), - 0x96 => visitor.visit_i16x8_min_s(), - 0x97 => visitor.visit_i16x8_min_u(), - 0x98 => visitor.visit_i16x8_max_s(), - 0x99 => visitor.visit_i16x8_max_u(), - 0x9b => visitor.visit_i16x8_avgr_u(), - 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(), - 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(), - 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(), - 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(), - 0xa0 => visitor.visit_i32x4_abs(), - 0xa1 => visitor.visit_i32x4_neg(), - 0xa3 => visitor.visit_i32x4_all_true(), - 0xa4 => visitor.visit_i32x4_bitmask(), - 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(), - 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(), - 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(), - 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(), - 0xab => visitor.visit_i32x4_shl(), - 0xac => visitor.visit_i32x4_shr_s(), - 0xad => visitor.visit_i32x4_shr_u(), - 0xae => visitor.visit_i32x4_add(), - 0xb1 => visitor.visit_i32x4_sub(), - 0xb5 => visitor.visit_i32x4_mul(), - 0xb6 => visitor.visit_i32x4_min_s(), - 0xb7 => visitor.visit_i32x4_min_u(), - 0xb8 => visitor.visit_i32x4_max_s(), - 0xb9 => visitor.visit_i32x4_max_u(), - 0xba => visitor.visit_i32x4_dot_i16x8_s(), - 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(), - 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(), - 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(), - 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(), - 0xc0 => visitor.visit_i64x2_abs(), - 0xc1 => visitor.visit_i64x2_neg(), - 0xc3 => visitor.visit_i64x2_all_true(), - 0xc4 => visitor.visit_i64x2_bitmask(), - 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(), - 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(), - 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(), - 0xca => visitor.visit_i64x2_extend_high_i32x4_u(), - 0xcb => visitor.visit_i64x2_shl(), - 0xcc => visitor.visit_i64x2_shr_s(), - 0xcd => visitor.visit_i64x2_shr_u(), - 0xce => visitor.visit_i64x2_add(), - 0xd1 => visitor.visit_i64x2_sub(), - 0xd5 => visitor.visit_i64x2_mul(), - 0xd6 => visitor.visit_i64x2_eq(), - 0xd7 => visitor.visit_i64x2_ne(), - 0xd8 => visitor.visit_i64x2_lt_s(), - 0xd9 => visitor.visit_i64x2_gt_s(), - 0xda => visitor.visit_i64x2_le_s(), - 0xdb => visitor.visit_i64x2_ge_s(), - 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(), - 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(), - 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(), - 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(), - 0xe0 => visitor.visit_f32x4_abs(), - 0xe1 => visitor.visit_f32x4_neg(), - 0xe3 => visitor.visit_f32x4_sqrt(), - 0xe4 => visitor.visit_f32x4_add(), - 0xe5 => visitor.visit_f32x4_sub(), - 0xe6 => visitor.visit_f32x4_mul(), - 0xe7 => visitor.visit_f32x4_div(), - 0xe8 => visitor.visit_f32x4_min(), - 0xe9 => visitor.visit_f32x4_max(), - 0xea => visitor.visit_f32x4_pmin(), - 0xeb => visitor.visit_f32x4_pmax(), - 0xec => visitor.visit_f64x2_abs(), - 0xed => visitor.visit_f64x2_neg(), - 0xef => visitor.visit_f64x2_sqrt(), - 0xf0 => visitor.visit_f64x2_add(), - 0xf1 => visitor.visit_f64x2_sub(), - 0xf2 => visitor.visit_f64x2_mul(), - 0xf3 => visitor.visit_f64x2_div(), - 0xf4 => visitor.visit_f64x2_min(), - 0xf5 => visitor.visit_f64x2_max(), - 0xf6 => visitor.visit_f64x2_pmin(), - 0xf7 => visitor.visit_f64x2_pmax(), - 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(), - 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(), - 0xfa => visitor.visit_f32x4_convert_i32x4_s(), - 0xfb => visitor.visit_f32x4_convert_i32x4_u(), - 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(), - 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(), - 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(), - 0xff => visitor.visit_f64x2_convert_low_i32x4_u(), - 0x100 => visitor.visit_i8x16_relaxed_swizzle(), - 0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(), - 0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(), - 0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(), - 0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(), - 0x105 => visitor.visit_f32x4_relaxed_madd(), - 0x106 => visitor.visit_f32x4_relaxed_nmadd(), - 0x107 => visitor.visit_f64x2_relaxed_madd(), - 0x108 => visitor.visit_f64x2_relaxed_nmadd(), - 0x109 => visitor.visit_i8x16_relaxed_laneselect(), - 0x10a => visitor.visit_i16x8_relaxed_laneselect(), - 0x10b => visitor.visit_i32x4_relaxed_laneselect(), - 0x10c => visitor.visit_i64x2_relaxed_laneselect(), - 0x10d => visitor.visit_f32x4_relaxed_min(), - 0x10e => visitor.visit_f32x4_relaxed_max(), - 0x10f => visitor.visit_f64x2_relaxed_min(), - 0x110 => visitor.visit_f64x2_relaxed_max(), - 0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(), - 0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(), - 0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(), - - _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"), - }) - } - fn visit_0xfe_operator( &mut self, pos: usize, @@ -1887,6 +1580,7 @@ impl<'a> BinaryReader<'a> { self.remaining_buffer() == &[0x0b] } + #[cfg(feature = "simd")] fn read_lane_index(&mut self, max: u8) -> Result { let index = self.read_u8()?; if index >= max { @@ -1898,6 +1592,7 @@ impl<'a> BinaryReader<'a> { Ok(index) } + #[cfg(feature = "simd")] fn read_v128(&mut self) -> Result { let mut bytes = [0; 16]; bytes.clone_from_slice(self.read_bytes(16)?); @@ -2100,7 +1795,17 @@ macro_rules! define_visit_operator { impl<'a> VisitOperator<'a> for OperatorFactory<'a> { type Output = Operator<'a>; - for_each_operator!(define_visit_operator); + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + crate::for_each_visit_operator!(define_visit_operator); +} + +#[cfg(feature = "simd")] +impl<'a> VisitSimdOperator<'a> for OperatorFactory<'a> { + crate::for_each_visit_simd_operator!(define_visit_operator); } /// Iterator returned from [`BinaryReader::read_iter`]. diff --git a/crates/wasmparser/src/binary_reader/simd.rs b/crates/wasmparser/src/binary_reader/simd.rs new file mode 100644 index 0000000000..7d5854c582 --- /dev/null +++ b/crates/wasmparser/src/binary_reader/simd.rs @@ -0,0 +1,320 @@ +use super::BinaryReader; +use crate::{Result, VisitOperator, VisitSimdOperator}; + +impl<'a> BinaryReader<'a> { + pub(super) fn visit_0xfd_operator( + &mut self, + pos: usize, + visitor: &mut T, + ) -> Result<>::Output> + where + T: VisitSimdOperator<'a>, + { + let code = self.read_var_u32()?; + Ok(match code { + 0x00 => visitor.visit_v128_load(self.read_memarg(4)?), + 0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?), + 0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?), + 0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?), + 0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?), + 0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?), + 0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?), + 0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?), + 0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?), + 0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?), + 0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?), + + 0x0b => visitor.visit_v128_store(self.read_memarg(4)?), + 0x0c => visitor.visit_v128_const(self.read_v128()?), + 0x0d => { + let mut lanes: [u8; 16] = [0; 16]; + for lane in &mut lanes { + *lane = self.read_lane_index(32)? + } + visitor.visit_i8x16_shuffle(lanes) + } + + 0x0e => visitor.visit_i8x16_swizzle(), + 0x0f => visitor.visit_i8x16_splat(), + 0x10 => visitor.visit_i16x8_splat(), + 0x11 => visitor.visit_i32x4_splat(), + 0x12 => visitor.visit_i64x2_splat(), + 0x13 => visitor.visit_f32x4_splat(), + 0x14 => visitor.visit_f64x2_splat(), + + 0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index(16)?), + 0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index(16)?), + 0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index(16)?), + 0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index(8)?), + 0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index(8)?), + 0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index(8)?), + 0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index(4)?), + + 0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index(4)?), + 0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index(2)?), + 0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index(2)?), + 0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index(4)?), + 0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index(4)?), + 0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index(2)?), + 0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index(2)?), + + 0x23 => visitor.visit_i8x16_eq(), + 0x24 => visitor.visit_i8x16_ne(), + 0x25 => visitor.visit_i8x16_lt_s(), + 0x26 => visitor.visit_i8x16_lt_u(), + 0x27 => visitor.visit_i8x16_gt_s(), + 0x28 => visitor.visit_i8x16_gt_u(), + 0x29 => visitor.visit_i8x16_le_s(), + 0x2a => visitor.visit_i8x16_le_u(), + 0x2b => visitor.visit_i8x16_ge_s(), + 0x2c => visitor.visit_i8x16_ge_u(), + 0x2d => visitor.visit_i16x8_eq(), + 0x2e => visitor.visit_i16x8_ne(), + 0x2f => visitor.visit_i16x8_lt_s(), + 0x30 => visitor.visit_i16x8_lt_u(), + 0x31 => visitor.visit_i16x8_gt_s(), + 0x32 => visitor.visit_i16x8_gt_u(), + 0x33 => visitor.visit_i16x8_le_s(), + 0x34 => visitor.visit_i16x8_le_u(), + 0x35 => visitor.visit_i16x8_ge_s(), + 0x36 => visitor.visit_i16x8_ge_u(), + 0x37 => visitor.visit_i32x4_eq(), + 0x38 => visitor.visit_i32x4_ne(), + 0x39 => visitor.visit_i32x4_lt_s(), + 0x3a => visitor.visit_i32x4_lt_u(), + 0x3b => visitor.visit_i32x4_gt_s(), + 0x3c => visitor.visit_i32x4_gt_u(), + 0x3d => visitor.visit_i32x4_le_s(), + 0x3e => visitor.visit_i32x4_le_u(), + 0x3f => visitor.visit_i32x4_ge_s(), + 0x40 => visitor.visit_i32x4_ge_u(), + 0x41 => visitor.visit_f32x4_eq(), + 0x42 => visitor.visit_f32x4_ne(), + 0x43 => visitor.visit_f32x4_lt(), + 0x44 => visitor.visit_f32x4_gt(), + 0x45 => visitor.visit_f32x4_le(), + 0x46 => visitor.visit_f32x4_ge(), + 0x47 => visitor.visit_f64x2_eq(), + 0x48 => visitor.visit_f64x2_ne(), + 0x49 => visitor.visit_f64x2_lt(), + 0x4a => visitor.visit_f64x2_gt(), + 0x4b => visitor.visit_f64x2_le(), + 0x4c => visitor.visit_f64x2_ge(), + 0x4d => visitor.visit_v128_not(), + 0x4e => visitor.visit_v128_and(), + 0x4f => visitor.visit_v128_andnot(), + 0x50 => visitor.visit_v128_or(), + 0x51 => visitor.visit_v128_xor(), + 0x52 => visitor.visit_v128_bitselect(), + 0x53 => visitor.visit_v128_any_true(), + + 0x54 => { + let memarg = self.read_memarg(0)?; + let lane = self.read_lane_index(16)?; + visitor.visit_v128_load8_lane(memarg, lane) + } + 0x55 => { + let memarg = self.read_memarg(1)?; + let lane = self.read_lane_index(8)?; + visitor.visit_v128_load16_lane(memarg, lane) + } + 0x56 => { + let memarg = self.read_memarg(2)?; + let lane = self.read_lane_index(4)?; + visitor.visit_v128_load32_lane(memarg, lane) + } + 0x57 => { + let memarg = self.read_memarg(3)?; + let lane = self.read_lane_index(2)?; + visitor.visit_v128_load64_lane(memarg, lane) + } + 0x58 => { + let memarg = self.read_memarg(0)?; + let lane = self.read_lane_index(16)?; + visitor.visit_v128_store8_lane(memarg, lane) + } + 0x59 => { + let memarg = self.read_memarg(1)?; + let lane = self.read_lane_index(8)?; + visitor.visit_v128_store16_lane(memarg, lane) + } + 0x5a => { + let memarg = self.read_memarg(2)?; + let lane = self.read_lane_index(4)?; + visitor.visit_v128_store32_lane(memarg, lane) + } + 0x5b => { + let memarg = self.read_memarg(3)?; + let lane = self.read_lane_index(2)?; + visitor.visit_v128_store64_lane(memarg, lane) + } + + 0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?), + 0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?), + 0x5e => visitor.visit_f32x4_demote_f64x2_zero(), + 0x5f => visitor.visit_f64x2_promote_low_f32x4(), + 0x60 => visitor.visit_i8x16_abs(), + 0x61 => visitor.visit_i8x16_neg(), + 0x62 => visitor.visit_i8x16_popcnt(), + 0x63 => visitor.visit_i8x16_all_true(), + 0x64 => visitor.visit_i8x16_bitmask(), + 0x65 => visitor.visit_i8x16_narrow_i16x8_s(), + 0x66 => visitor.visit_i8x16_narrow_i16x8_u(), + 0x67 => visitor.visit_f32x4_ceil(), + 0x68 => visitor.visit_f32x4_floor(), + 0x69 => visitor.visit_f32x4_trunc(), + 0x6a => visitor.visit_f32x4_nearest(), + 0x6b => visitor.visit_i8x16_shl(), + 0x6c => visitor.visit_i8x16_shr_s(), + 0x6d => visitor.visit_i8x16_shr_u(), + 0x6e => visitor.visit_i8x16_add(), + 0x6f => visitor.visit_i8x16_add_sat_s(), + 0x70 => visitor.visit_i8x16_add_sat_u(), + 0x71 => visitor.visit_i8x16_sub(), + 0x72 => visitor.visit_i8x16_sub_sat_s(), + 0x73 => visitor.visit_i8x16_sub_sat_u(), + 0x74 => visitor.visit_f64x2_ceil(), + 0x75 => visitor.visit_f64x2_floor(), + 0x76 => visitor.visit_i8x16_min_s(), + 0x77 => visitor.visit_i8x16_min_u(), + 0x78 => visitor.visit_i8x16_max_s(), + 0x79 => visitor.visit_i8x16_max_u(), + 0x7a => visitor.visit_f64x2_trunc(), + 0x7b => visitor.visit_i8x16_avgr_u(), + 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(), + 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(), + 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(), + 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(), + 0x80 => visitor.visit_i16x8_abs(), + 0x81 => visitor.visit_i16x8_neg(), + 0x82 => visitor.visit_i16x8_q15mulr_sat_s(), + 0x83 => visitor.visit_i16x8_all_true(), + 0x84 => visitor.visit_i16x8_bitmask(), + 0x85 => visitor.visit_i16x8_narrow_i32x4_s(), + 0x86 => visitor.visit_i16x8_narrow_i32x4_u(), + 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(), + 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(), + 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(), + 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(), + 0x8b => visitor.visit_i16x8_shl(), + 0x8c => visitor.visit_i16x8_shr_s(), + 0x8d => visitor.visit_i16x8_shr_u(), + 0x8e => visitor.visit_i16x8_add(), + 0x8f => visitor.visit_i16x8_add_sat_s(), + 0x90 => visitor.visit_i16x8_add_sat_u(), + 0x91 => visitor.visit_i16x8_sub(), + 0x92 => visitor.visit_i16x8_sub_sat_s(), + 0x93 => visitor.visit_i16x8_sub_sat_u(), + 0x94 => visitor.visit_f64x2_nearest(), + 0x95 => visitor.visit_i16x8_mul(), + 0x96 => visitor.visit_i16x8_min_s(), + 0x97 => visitor.visit_i16x8_min_u(), + 0x98 => visitor.visit_i16x8_max_s(), + 0x99 => visitor.visit_i16x8_max_u(), + 0x9b => visitor.visit_i16x8_avgr_u(), + 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(), + 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(), + 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(), + 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(), + 0xa0 => visitor.visit_i32x4_abs(), + 0xa1 => visitor.visit_i32x4_neg(), + 0xa3 => visitor.visit_i32x4_all_true(), + 0xa4 => visitor.visit_i32x4_bitmask(), + 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(), + 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(), + 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(), + 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(), + 0xab => visitor.visit_i32x4_shl(), + 0xac => visitor.visit_i32x4_shr_s(), + 0xad => visitor.visit_i32x4_shr_u(), + 0xae => visitor.visit_i32x4_add(), + 0xb1 => visitor.visit_i32x4_sub(), + 0xb5 => visitor.visit_i32x4_mul(), + 0xb6 => visitor.visit_i32x4_min_s(), + 0xb7 => visitor.visit_i32x4_min_u(), + 0xb8 => visitor.visit_i32x4_max_s(), + 0xb9 => visitor.visit_i32x4_max_u(), + 0xba => visitor.visit_i32x4_dot_i16x8_s(), + 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(), + 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(), + 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(), + 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(), + 0xc0 => visitor.visit_i64x2_abs(), + 0xc1 => visitor.visit_i64x2_neg(), + 0xc3 => visitor.visit_i64x2_all_true(), + 0xc4 => visitor.visit_i64x2_bitmask(), + 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(), + 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(), + 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(), + 0xca => visitor.visit_i64x2_extend_high_i32x4_u(), + 0xcb => visitor.visit_i64x2_shl(), + 0xcc => visitor.visit_i64x2_shr_s(), + 0xcd => visitor.visit_i64x2_shr_u(), + 0xce => visitor.visit_i64x2_add(), + 0xd1 => visitor.visit_i64x2_sub(), + 0xd5 => visitor.visit_i64x2_mul(), + 0xd6 => visitor.visit_i64x2_eq(), + 0xd7 => visitor.visit_i64x2_ne(), + 0xd8 => visitor.visit_i64x2_lt_s(), + 0xd9 => visitor.visit_i64x2_gt_s(), + 0xda => visitor.visit_i64x2_le_s(), + 0xdb => visitor.visit_i64x2_ge_s(), + 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(), + 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(), + 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(), + 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(), + 0xe0 => visitor.visit_f32x4_abs(), + 0xe1 => visitor.visit_f32x4_neg(), + 0xe3 => visitor.visit_f32x4_sqrt(), + 0xe4 => visitor.visit_f32x4_add(), + 0xe5 => visitor.visit_f32x4_sub(), + 0xe6 => visitor.visit_f32x4_mul(), + 0xe7 => visitor.visit_f32x4_div(), + 0xe8 => visitor.visit_f32x4_min(), + 0xe9 => visitor.visit_f32x4_max(), + 0xea => visitor.visit_f32x4_pmin(), + 0xeb => visitor.visit_f32x4_pmax(), + 0xec => visitor.visit_f64x2_abs(), + 0xed => visitor.visit_f64x2_neg(), + 0xef => visitor.visit_f64x2_sqrt(), + 0xf0 => visitor.visit_f64x2_add(), + 0xf1 => visitor.visit_f64x2_sub(), + 0xf2 => visitor.visit_f64x2_mul(), + 0xf3 => visitor.visit_f64x2_div(), + 0xf4 => visitor.visit_f64x2_min(), + 0xf5 => visitor.visit_f64x2_max(), + 0xf6 => visitor.visit_f64x2_pmin(), + 0xf7 => visitor.visit_f64x2_pmax(), + 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(), + 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(), + 0xfa => visitor.visit_f32x4_convert_i32x4_s(), + 0xfb => visitor.visit_f32x4_convert_i32x4_u(), + 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(), + 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(), + 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(), + 0xff => visitor.visit_f64x2_convert_low_i32x4_u(), + 0x100 => visitor.visit_i8x16_relaxed_swizzle(), + 0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(), + 0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(), + 0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(), + 0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(), + 0x105 => visitor.visit_f32x4_relaxed_madd(), + 0x106 => visitor.visit_f32x4_relaxed_nmadd(), + 0x107 => visitor.visit_f64x2_relaxed_madd(), + 0x108 => visitor.visit_f64x2_relaxed_nmadd(), + 0x109 => visitor.visit_i8x16_relaxed_laneselect(), + 0x10a => visitor.visit_i16x8_relaxed_laneselect(), + 0x10b => visitor.visit_i32x4_relaxed_laneselect(), + 0x10c => visitor.visit_i64x2_relaxed_laneselect(), + 0x10d => visitor.visit_f32x4_relaxed_min(), + 0x10e => visitor.visit_f32x4_relaxed_max(), + 0x10f => visitor.visit_f64x2_relaxed_min(), + 0x110 => visitor.visit_f64x2_relaxed_max(), + 0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(), + 0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(), + 0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(), + + _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"), + }) + } +} diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index 0fa70dea2d..7a7d8b027c 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -55,6 +55,878 @@ mod prelude { pub use crate::collections::{IndexMap, Map, Set}; } +/// A helper macro which is used to itself define further macros below. +/// +/// This is a little complicated, so first off sorry about that. The idea here +/// though is that there's one source of truth for the listing of instructions +/// in `wasmparser` and this is the one location. All other locations should be +/// derivative from this. As this one source of truth it has all instructions +/// from all proposals all grouped together. Down below though, for compile +/// time, currently the simd instructions are split out into their own macro. +/// The structure/syntax of this macro is to facilitate easily splitting out +/// entire groups of instructions. +/// +/// This is used below to define more macros. +macro_rules! _for_each_operator_group { + ($mac:ident) => { + $mac! { + @mvp { + Unreachable => visit_unreachable (arity 0 -> 0) + Nop => visit_nop (arity 0 -> 0) + Block { blockty: $crate::BlockType } => visit_block (arity block -> ~block) + Loop { blockty: $crate::BlockType } => visit_loop (arity block -> ~block) + If { blockty: $crate::BlockType } => visit_if (arity 1 block -> ~block) + Else => visit_else (arity ~end -> ~end) + End => visit_end (arity implicit_else ~end -> implicit_else end) + Br { relative_depth: u32 } => visit_br (arity br -> 0) + BrIf { relative_depth: u32 } => visit_br_if (arity 1 br -> br) + BrTable { targets: $crate::BrTable<'a> } => visit_br_table (arity 1 br_table -> 0) + Return => visit_return (arity ~ret -> 0) + Call { function_index: u32 } => visit_call (arity func -> func) + CallIndirect { type_index: u32, table_index: u32 } => visit_call_indirect (arity 1 type -> type) + Drop => visit_drop (arity 1 -> 0) + Select => visit_select (arity 3 -> 1) + LocalGet { local_index: u32 } => visit_local_get (arity 0 -> 1) + LocalSet { local_index: u32 } => visit_local_set (arity 1 -> 0) + LocalTee { local_index: u32 } => visit_local_tee (arity 1 -> 1) + GlobalGet { global_index: u32 } => visit_global_get (arity 0 -> 1) + GlobalSet { global_index: u32 } => visit_global_set (arity 1 -> 0) + I32Load { memarg: $crate::MemArg } => visit_i32_load (load i32) + I64Load { memarg: $crate::MemArg } => visit_i64_load (load i64) + F32Load { memarg: $crate::MemArg } => visit_f32_load (load f32) + F64Load { memarg: $crate::MemArg } => visit_f64_load (load f64) + I32Load8S { memarg: $crate::MemArg } => visit_i32_load8_s (load i32) + I32Load8U { memarg: $crate::MemArg } => visit_i32_load8_u (load i32) + I32Load16S { memarg: $crate::MemArg } => visit_i32_load16_s (load i32) + I32Load16U { memarg: $crate::MemArg } => visit_i32_load16_u (load i32) + I64Load8S { memarg: $crate::MemArg } => visit_i64_load8_s (load i64) + I64Load8U { memarg: $crate::MemArg } => visit_i64_load8_u (load i64) + I64Load16S { memarg: $crate::MemArg } => visit_i64_load16_s (load i64) + I64Load16U { memarg: $crate::MemArg } => visit_i64_load16_u (load i64) + I64Load32S { memarg: $crate::MemArg } => visit_i64_load32_s (load i64) + I64Load32U { memarg: $crate::MemArg } => visit_i64_load32_u (load i64) + I32Store { memarg: $crate::MemArg } => visit_i32_store (store i32) + I64Store { memarg: $crate::MemArg } => visit_i64_store (store i64) + F32Store { memarg: $crate::MemArg } => visit_f32_store (store f32) + F64Store { memarg: $crate::MemArg } => visit_f64_store (store f64) + I32Store8 { memarg: $crate::MemArg } => visit_i32_store8 (store i32) + I32Store16 { memarg: $crate::MemArg } => visit_i32_store16 (store i32) + I64Store8 { memarg: $crate::MemArg } => visit_i64_store8 (store i64) + I64Store16 { memarg: $crate::MemArg } => visit_i64_store16 (store i64) + I64Store32 { memarg: $crate::MemArg } => visit_i64_store32 (store i64) + MemorySize { mem: u32 } => visit_memory_size (arity 0 -> 1) + MemoryGrow { mem: u32 } => visit_memory_grow (arity 1 -> 1) + I32Const { value: i32 } => visit_i32_const (push i32) + I64Const { value: i64 } => visit_i64_const (push i64) + F32Const { value: $crate::Ieee32 } => visit_f32_const (push f32) + F64Const { value: $crate::Ieee64 } => visit_f64_const (push f64) + I32Eqz => visit_i32_eqz (test i32) + I32Eq => visit_i32_eq (cmp i32) + I32Ne => visit_i32_ne (cmp i32) + I32LtS => visit_i32_lt_s (cmp i32) + I32LtU => visit_i32_lt_u (cmp i32) + I32GtS => visit_i32_gt_s (cmp i32) + I32GtU => visit_i32_gt_u (cmp i32) + I32LeS => visit_i32_le_s (cmp i32) + I32LeU => visit_i32_le_u (cmp i32) + I32GeS => visit_i32_ge_s (cmp i32) + I32GeU => visit_i32_ge_u (cmp i32) + I64Eqz => visit_i64_eqz (test i64) + I64Eq => visit_i64_eq (cmp i64) + I64Ne => visit_i64_ne (cmp i64) + I64LtS => visit_i64_lt_s (cmp i64) + I64LtU => visit_i64_lt_u (cmp i64) + I64GtS => visit_i64_gt_s (cmp i64) + I64GtU => visit_i64_gt_u (cmp i64) + I64LeS => visit_i64_le_s (cmp i64) + I64LeU => visit_i64_le_u (cmp i64) + I64GeS => visit_i64_ge_s (cmp i64) + I64GeU => visit_i64_ge_u (cmp i64) + F32Eq => visit_f32_eq (cmp f32) + F32Ne => visit_f32_ne (cmp f32) + F32Lt => visit_f32_lt (cmp f32) + F32Gt => visit_f32_gt (cmp f32) + F32Le => visit_f32_le (cmp f32) + F32Ge => visit_f32_ge (cmp f32) + F64Eq => visit_f64_eq (cmp f64) + F64Ne => visit_f64_ne (cmp f64) + F64Lt => visit_f64_lt (cmp f64) + F64Gt => visit_f64_gt (cmp f64) + F64Le => visit_f64_le (cmp f64) + F64Ge => visit_f64_ge (cmp f64) + I32Clz => visit_i32_clz (unary i32) + I32Ctz => visit_i32_ctz (unary i32) + I32Popcnt => visit_i32_popcnt (unary i32) + I32Add => visit_i32_add (binary i32) + I32Sub => visit_i32_sub (binary i32) + I32Mul => visit_i32_mul (binary i32) + I32DivS => visit_i32_div_s (binary i32) + I32DivU => visit_i32_div_u (binary i32) + I32RemS => visit_i32_rem_s (binary i32) + I32RemU => visit_i32_rem_u (binary i32) + I32And => visit_i32_and (binary i32) + I32Or => visit_i32_or (binary i32) + I32Xor => visit_i32_xor (binary i32) + I32Shl => visit_i32_shl (binary i32) + I32ShrS => visit_i32_shr_s (binary i32) + I32ShrU => visit_i32_shr_u (binary i32) + I32Rotl => visit_i32_rotl (binary i32) + I32Rotr => visit_i32_rotr (binary i32) + I64Clz => visit_i64_clz (unary i64) + I64Ctz => visit_i64_ctz (unary i64) + I64Popcnt => visit_i64_popcnt (unary i64) + I64Add => visit_i64_add (binary i64) + I64Sub => visit_i64_sub (binary i64) + I64Mul => visit_i64_mul (binary i64) + I64DivS => visit_i64_div_s (binary i64) + I64DivU => visit_i64_div_u (binary i64) + I64RemS => visit_i64_rem_s (binary i64) + I64RemU => visit_i64_rem_u (binary i64) + I64And => visit_i64_and (binary i64) + I64Or => visit_i64_or (binary i64) + I64Xor => visit_i64_xor (binary i64) + I64Shl => visit_i64_shl (binary i64) + I64ShrS => visit_i64_shr_s (binary i64) + I64ShrU => visit_i64_shr_u (binary i64) + I64Rotl => visit_i64_rotl (binary i64) + I64Rotr => visit_i64_rotr (binary i64) + F32Abs => visit_f32_abs (unary f32) + F32Neg => visit_f32_neg (unary f32) + F32Ceil => visit_f32_ceil (unary f32) + F32Floor => visit_f32_floor (unary f32) + F32Trunc => visit_f32_trunc (unary f32) + F32Nearest => visit_f32_nearest (unary f32) + F32Sqrt => visit_f32_sqrt (unary f32) + F32Add => visit_f32_add (binary f32) + F32Sub => visit_f32_sub (binary f32) + F32Mul => visit_f32_mul (binary f32) + F32Div => visit_f32_div (binary f32) + F32Min => visit_f32_min (binary f32) + F32Max => visit_f32_max (binary f32) + F32Copysign => visit_f32_copysign (binary f32) + F64Abs => visit_f64_abs (unary f64) + F64Neg => visit_f64_neg (unary f64) + F64Ceil => visit_f64_ceil (unary f64) + F64Floor => visit_f64_floor (unary f64) + F64Trunc => visit_f64_trunc (unary f64) + F64Nearest => visit_f64_nearest (unary f64) + F64Sqrt => visit_f64_sqrt (unary f64) + F64Add => visit_f64_add (binary f64) + F64Sub => visit_f64_sub (binary f64) + F64Mul => visit_f64_mul (binary f64) + F64Div => visit_f64_div (binary f64) + F64Min => visit_f64_min (binary f64) + F64Max => visit_f64_max (binary f64) + F64Copysign => visit_f64_copysign (binary f64) + I32WrapI64 => visit_i32_wrap_i64 (conversion i32 i64) + I32TruncF32S => visit_i32_trunc_f32_s (conversion i32 f32) + I32TruncF32U => visit_i32_trunc_f32_u (conversion i32 f32) + I32TruncF64S => visit_i32_trunc_f64_s (conversion i32 f64) + I32TruncF64U => visit_i32_trunc_f64_u (conversion i32 f64) + I64ExtendI32S => visit_i64_extend_i32_s (conversion i64 i32) + I64ExtendI32U => visit_i64_extend_i32_u (conversion i64 i32) + I64TruncF32S => visit_i64_trunc_f32_s (conversion i64 f32) + I64TruncF32U => visit_i64_trunc_f32_u (conversion i64 f32) + I64TruncF64S => visit_i64_trunc_f64_s (conversion i64 f64) + I64TruncF64U => visit_i64_trunc_f64_u (conversion i64 f64) + F32ConvertI32S => visit_f32_convert_i32_s (conversion f32 i32) + F32ConvertI32U => visit_f32_convert_i32_u (conversion f32 i32) + F32ConvertI64S => visit_f32_convert_i64_s (conversion f32 i64) + F32ConvertI64U => visit_f32_convert_i64_u (conversion f32 i64) + F32DemoteF64 => visit_f32_demote_f64 (conversion f32 f64) + F64ConvertI32S => visit_f64_convert_i32_s (conversion f64 i32) + F64ConvertI32U => visit_f64_convert_i32_u (conversion f64 i32) + F64ConvertI64S => visit_f64_convert_i64_s (conversion f64 i64) + F64ConvertI64U => visit_f64_convert_i64_u (conversion f64 i64) + F64PromoteF32 => visit_f64_promote_f32 (conversion f64 f32) + I32ReinterpretF32 => visit_i32_reinterpret_f32 (conversion i32 f32) + I64ReinterpretF64 => visit_i64_reinterpret_f64 (conversion i64 f64) + F32ReinterpretI32 => visit_f32_reinterpret_i32 (conversion f32 i32) + F64ReinterpretI64 => visit_f64_reinterpret_i64 (conversion f64 i64) + } + + @sign_extension { + I32Extend8S => visit_i32_extend8_s (unary i32) + I32Extend16S => visit_i32_extend16_s (unary i32) + I64Extend8S => visit_i64_extend8_s (unary i64) + I64Extend16S => visit_i64_extend16_s (unary i64) + I64Extend32S => visit_i64_extend32_s (unary i64) + } + + // 0xFB prefixed operators + // Garbage Collection + // http://github.com/WebAssembly/gc + @gc { + RefEq => visit_ref_eq (arity 2 -> 1) + StructNew { struct_type_index: u32 } => visit_struct_new (arity type -> 1) + StructNewDefault { struct_type_index: u32 } => visit_struct_new_default (arity 0 -> 1) + StructGet { struct_type_index: u32, field_index: u32 } => visit_struct_get (arity 1 -> 1) + StructGetS { struct_type_index: u32, field_index: u32 } => visit_struct_get_s (arity 1 -> 1) + StructGetU { struct_type_index: u32, field_index: u32 } => visit_struct_get_u (arity 1 -> 1) + StructSet { struct_type_index: u32, field_index: u32 } => visit_struct_set (arity 2 -> 0) + ArrayNew { array_type_index: u32 } => visit_array_new (arity 2 -> 1) + ArrayNewDefault { array_type_index: u32 } => visit_array_new_default (arity 1 -> 1) + ArrayNewFixed { array_type_index: u32, array_size: u32 } => visit_array_new_fixed (arity size -> 1) + ArrayNewData { array_type_index: u32, array_data_index: u32 } => visit_array_new_data (arity 2 -> 1) + ArrayNewElem { array_type_index: u32, array_elem_index: u32 } => visit_array_new_elem (arity 2 -> 1) + ArrayGet { array_type_index: u32 } => visit_array_get (arity 2 -> 1) + ArrayGetS { array_type_index: u32 } => visit_array_get_s (arity 2 -> 1) + ArrayGetU { array_type_index: u32 } => visit_array_get_u (arity 2 -> 1) + ArraySet { array_type_index: u32 } => visit_array_set (arity 3 -> 0) + ArrayLen => visit_array_len (arity 1 -> 1) + ArrayFill { array_type_index: u32 } => visit_array_fill (arity 4 -> 0) + ArrayCopy { array_type_index_dst: u32, array_type_index_src: u32 } => visit_array_copy (arity 5 -> 0) + ArrayInitData { array_type_index: u32, array_data_index: u32 } => visit_array_init_data (arity 4 -> 0) + ArrayInitElem { array_type_index: u32, array_elem_index: u32 } => visit_array_init_elem (arity 4 -> 0) + RefTestNonNull { hty: $crate::HeapType } => visit_ref_test_non_null (arity 1 -> 1) + RefTestNullable { hty: $crate::HeapType } => visit_ref_test_nullable (arity 1 -> 1) + RefCastNonNull { hty: $crate::HeapType } => visit_ref_cast_non_null (arity 1 -> 1) + RefCastNullable { hty: $crate::HeapType } => visit_ref_cast_nullable (arity 1 -> 1) + BrOnCast { + relative_depth: u32, + from_ref_type: $crate::RefType, + to_ref_type: $crate::RefType + } => visit_br_on_cast (arity br -> br) + BrOnCastFail { + relative_depth: u32, + from_ref_type: $crate::RefType, + to_ref_type: $crate::RefType + } => visit_br_on_cast_fail (arity br -> br) + AnyConvertExtern => visit_any_convert_extern (arity 1 -> 1) + ExternConvertAny => visit_extern_convert_any (arity 1 -> 1) + RefI31 => visit_ref_i31 (arity 1 -> 1) + I31GetS => visit_i31_get_s (arity 1 -> 1) + I31GetU => visit_i31_get_u (arity 1 -> 1) + } + + // 0xFC operators + // Non-trapping Float-to-int Conversions + // https://github.com/WebAssembly/nontrapping-float-to-int-conversions + @saturating_float_to_int { + I32TruncSatF32S => visit_i32_trunc_sat_f32_s (conversion i32 f32) + I32TruncSatF32U => visit_i32_trunc_sat_f32_u (conversion i32 f32) + I32TruncSatF64S => visit_i32_trunc_sat_f64_s (conversion i32 f64) + I32TruncSatF64U => visit_i32_trunc_sat_f64_u (conversion i32 f64) + I64TruncSatF32S => visit_i64_trunc_sat_f32_s (conversion i64 f32) + I64TruncSatF32U => visit_i64_trunc_sat_f32_u (conversion i64 f32) + I64TruncSatF64S => visit_i64_trunc_sat_f64_s (conversion i64 f64) + I64TruncSatF64U => visit_i64_trunc_sat_f64_u (conversion i64 f64) + } + + // 0xFC prefixed operators + // bulk memory operations + // https://github.com/WebAssembly/bulk-memory-operations + @bulk_memory { + MemoryInit { data_index: u32, mem: u32 } => visit_memory_init (arity 3 -> 0) + DataDrop { data_index: u32 } => visit_data_drop (arity 0 -> 0) + MemoryCopy { dst_mem: u32, src_mem: u32 } => visit_memory_copy (arity 3 -> 0) + MemoryFill { mem: u32 } => visit_memory_fill (arity 3 -> 0) + TableInit { elem_index: u32, table: u32 } => visit_table_init (arity 3 -> 0) + ElemDrop { elem_index: u32 } => visit_elem_drop (arity 0 -> 0) + TableCopy { dst_table: u32, src_table: u32 } => visit_table_copy (arity 3 -> 0) + } + + // 0xFC prefixed operators + // reference-types + // https://github.com/WebAssembly/reference-types + @reference_types { + TypedSelect { ty: $crate::ValType } => visit_typed_select (arity 3 -> 1) + RefNull { hty: $crate::HeapType } => visit_ref_null (arity 0 -> 1) + RefIsNull => visit_ref_is_null (arity 1 -> 1) + RefFunc { function_index: u32 } => visit_ref_func (arity 0 -> 1) + TableFill { table: u32 } => visit_table_fill (arity 3 -> 0) + TableGet { table: u32 } => visit_table_get (arity 1 -> 1) + TableSet { table: u32 } => visit_table_set (arity 2 -> 0) + TableGrow { table: u32 } => visit_table_grow (arity 2 -> 1) + TableSize { table: u32 } => visit_table_size (arity 0 -> 1) + } + + // Wasm tail-call proposal + // https://github.com/WebAssembly/tail-call + @tail_call { + ReturnCall { function_index: u32 } => visit_return_call (arity func -> 0) + ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect (arity 1 type -> 0) + } + + // OxFC prefixed operators + // memory control (experimental) + // https://github.com/WebAssembly/design/issues/1439 + @memory_control { + MemoryDiscard { mem: u32 } => visit_memory_discard (arity 2 -> 0) + } + + // 0xFE prefixed operators + // threads + // https://github.com/WebAssembly/threads + @threads { + MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify (atomic rmw i32) + MemoryAtomicWait32 { memarg: $crate::MemArg } => visit_memory_atomic_wait32 (arity 3 -> 1) + MemoryAtomicWait64 { memarg: $crate::MemArg } => visit_memory_atomic_wait64 (arity 3 -> 1) + AtomicFence => visit_atomic_fence (arity 0 -> 0) + I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load (load atomic i32) + I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load (load atomic i64) + I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u (load atomic i32) + I32AtomicLoad16U { memarg: $crate::MemArg } => visit_i32_atomic_load16_u (load atomic i32) + I64AtomicLoad8U { memarg: $crate::MemArg } => visit_i64_atomic_load8_u (load atomic i64) + I64AtomicLoad16U { memarg: $crate::MemArg } => visit_i64_atomic_load16_u (load atomic i64) + I64AtomicLoad32U { memarg: $crate::MemArg } => visit_i64_atomic_load32_u (load atomic i64) + I32AtomicStore { memarg: $crate::MemArg } => visit_i32_atomic_store (store atomic i32) + I64AtomicStore { memarg: $crate::MemArg } => visit_i64_atomic_store (store atomic i64) + I32AtomicStore8 { memarg: $crate::MemArg } => visit_i32_atomic_store8 (store atomic i32) + I32AtomicStore16 { memarg: $crate::MemArg } => visit_i32_atomic_store16 (store atomic i32) + I64AtomicStore8 { memarg: $crate::MemArg } => visit_i64_atomic_store8 (store atomic i64) + I64AtomicStore16 { memarg: $crate::MemArg } => visit_i64_atomic_store16 (store atomic i64) + I64AtomicStore32 { memarg: $crate::MemArg } => visit_i64_atomic_store32 (store atomic i64) + I32AtomicRmwAdd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_add (atomic rmw i32) + I64AtomicRmwAdd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_add (atomic rmw i64) + I32AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_add_u (atomic rmw i32) + I32AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_add_u (atomic rmw i32) + I64AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_add_u (atomic rmw i64) + I64AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_add_u (atomic rmw i64) + I64AtomicRmw32AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_add_u (atomic rmw i64) + I32AtomicRmwSub { memarg: $crate::MemArg } => visit_i32_atomic_rmw_sub (atomic rmw i32) + I64AtomicRmwSub { memarg: $crate::MemArg } => visit_i64_atomic_rmw_sub (atomic rmw i64) + I32AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_sub_u (atomic rmw i32) + I32AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_sub_u (atomic rmw i32) + I64AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_sub_u (atomic rmw i64) + I64AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_sub_u (atomic rmw i64) + I64AtomicRmw32SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_sub_u (atomic rmw i64) + I32AtomicRmwAnd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_and (atomic rmw i32) + I64AtomicRmwAnd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_and (atomic rmw i64) + I32AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_and_u (atomic rmw i32) + I32AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_and_u (atomic rmw i32) + I64AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_and_u (atomic rmw i64) + I64AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_and_u (atomic rmw i64) + I64AtomicRmw32AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_and_u (atomic rmw i64) + I32AtomicRmwOr { memarg: $crate::MemArg } => visit_i32_atomic_rmw_or (atomic rmw i32) + I64AtomicRmwOr { memarg: $crate::MemArg } => visit_i64_atomic_rmw_or (atomic rmw i64) + I32AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_or_u (atomic rmw i32) + I32AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_or_u (atomic rmw i32) + I64AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_or_u (atomic rmw i64) + I64AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_or_u (atomic rmw i64) + I64AtomicRmw32OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_or_u (atomic rmw i64) + I32AtomicRmwXor { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xor (atomic rmw i32) + I64AtomicRmwXor { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xor (atomic rmw i64) + I32AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xor_u (atomic rmw i32) + I32AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xor_u (atomic rmw i32) + I64AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xor_u (atomic rmw i64) + I64AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xor_u (atomic rmw i64) + I64AtomicRmw32XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xor_u (atomic rmw i64) + I32AtomicRmwXchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xchg (atomic rmw i32) + I64AtomicRmwXchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xchg (atomic rmw i64) + I32AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xchg_u (atomic rmw i32) + I32AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xchg_u (atomic rmw i32) + I64AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xchg_u (atomic rmw i64) + I64AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xchg_u (atomic rmw i64) + I64AtomicRmw32XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xchg_u (atomic rmw i64) + I32AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_cmpxchg (atomic cmpxchg i32) + I64AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_cmpxchg (atomic cmpxchg i64) + I32AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_cmpxchg_u (atomic cmpxchg i32) + I32AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_cmpxchg_u (atomic cmpxchg i32) + I64AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_cmpxchg_u (atomic cmpxchg i64) + I64AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_cmpxchg_u (atomic cmpxchg i64) + I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u (atomic cmpxchg i64) + } + + // 0xFD operators + // 128-bit SIMD + // - https://github.com/webassembly/simd + // - https://webassembly.github.io/simd/core/binary/instructions.html + @simd { + V128Load { memarg: $crate::MemArg } => visit_v128_load (load v128) + V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s (load v128) + V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u (load v128) + V128Load16x4S { memarg: $crate::MemArg } => visit_v128_load16x4_s (load v128) + V128Load16x4U { memarg: $crate::MemArg } => visit_v128_load16x4_u (load v128) + V128Load32x2S { memarg: $crate::MemArg } => visit_v128_load32x2_s (load v128) + V128Load32x2U { memarg: $crate::MemArg } => visit_v128_load32x2_u (load v128) + V128Load8Splat { memarg: $crate::MemArg } => visit_v128_load8_splat (load v128) + V128Load16Splat { memarg: $crate::MemArg } => visit_v128_load16_splat (load v128) + V128Load32Splat { memarg: $crate::MemArg } => visit_v128_load32_splat (load v128) + V128Load64Splat { memarg: $crate::MemArg } => visit_v128_load64_splat (load v128) + V128Load32Zero { memarg: $crate::MemArg } => visit_v128_load32_zero (load v128) + V128Load64Zero { memarg: $crate::MemArg } => visit_v128_load64_zero (load v128) + V128Store { memarg: $crate::MemArg } => visit_v128_store (store v128) + V128Load8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load8_lane (load lane 16) + V128Load16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load16_lane (load lane 8) + V128Load32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load32_lane (load lane 4) + V128Load64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load64_lane (load lane 2) + V128Store8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store8_lane (store lane 16) + V128Store16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store16_lane (store lane 8) + V128Store32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store32_lane (store lane 4) + V128Store64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store64_lane (store lane 2) + V128Const { value: $crate::V128 } => visit_v128_const (push v128) + I8x16Shuffle { lanes: [u8; 16] } => visit_i8x16_shuffle (arity 2 -> 1) + I8x16ExtractLaneS { lane: u8 } => visit_i8x16_extract_lane_s (extract i32 16) + I8x16ExtractLaneU { lane: u8 } => visit_i8x16_extract_lane_u (extract i32 16) + I8x16ReplaceLane { lane: u8 } => visit_i8x16_replace_lane (replace i32 16) + I16x8ExtractLaneS { lane: u8 } => visit_i16x8_extract_lane_s (extract i32 8) + I16x8ExtractLaneU { lane: u8 } => visit_i16x8_extract_lane_u (extract i32 8) + I16x8ReplaceLane { lane: u8 } => visit_i16x8_replace_lane (replace i32 8) + I32x4ExtractLane { lane: u8 } => visit_i32x4_extract_lane (extract i32 4) + I32x4ReplaceLane { lane: u8 } => visit_i32x4_replace_lane (replace i32 4) + I64x2ExtractLane { lane: u8 } => visit_i64x2_extract_lane (extract i64 2) + I64x2ReplaceLane { lane: u8 } => visit_i64x2_replace_lane (replace i64 2) + F32x4ExtractLane { lane: u8 } => visit_f32x4_extract_lane (extract f32 4) + F32x4ReplaceLane { lane: u8 } => visit_f32x4_replace_lane (replace f32 4) + F64x2ExtractLane { lane: u8 } => visit_f64x2_extract_lane (extract f64 2) + F64x2ReplaceLane { lane: u8 } => visit_f64x2_replace_lane (replace f64 2) + I8x16Swizzle => visit_i8x16_swizzle (binary v128) + I8x16Splat => visit_i8x16_splat (splat i32) + I16x8Splat => visit_i16x8_splat (splat i32) + I32x4Splat => visit_i32x4_splat (splat i32) + I64x2Splat => visit_i64x2_splat (splat i64) + F32x4Splat => visit_f32x4_splat (splat f32) + F64x2Splat => visit_f64x2_splat (splat f64) + I8x16Eq => visit_i8x16_eq (binary v128) + I8x16Ne => visit_i8x16_ne (binary v128) + I8x16LtS => visit_i8x16_lt_s (binary v128) + I8x16LtU => visit_i8x16_lt_u (binary v128) + I8x16GtS => visit_i8x16_gt_s (binary v128) + I8x16GtU => visit_i8x16_gt_u (binary v128) + I8x16LeS => visit_i8x16_le_s (binary v128) + I8x16LeU => visit_i8x16_le_u (binary v128) + I8x16GeS => visit_i8x16_ge_s (binary v128) + I8x16GeU => visit_i8x16_ge_u (binary v128) + I16x8Eq => visit_i16x8_eq (binary v128) + I16x8Ne => visit_i16x8_ne (binary v128) + I16x8LtS => visit_i16x8_lt_s (binary v128) + I16x8LtU => visit_i16x8_lt_u (binary v128) + I16x8GtS => visit_i16x8_gt_s (binary v128) + I16x8GtU => visit_i16x8_gt_u (binary v128) + I16x8LeS => visit_i16x8_le_s (binary v128) + I16x8LeU => visit_i16x8_le_u (binary v128) + I16x8GeS => visit_i16x8_ge_s (binary v128) + I16x8GeU => visit_i16x8_ge_u (binary v128) + I32x4Eq => visit_i32x4_eq (binary v128) + I32x4Ne => visit_i32x4_ne (binary v128) + I32x4LtS => visit_i32x4_lt_s (binary v128) + I32x4LtU => visit_i32x4_lt_u (binary v128) + I32x4GtS => visit_i32x4_gt_s (binary v128) + I32x4GtU => visit_i32x4_gt_u (binary v128) + I32x4LeS => visit_i32x4_le_s (binary v128) + I32x4LeU => visit_i32x4_le_u (binary v128) + I32x4GeS => visit_i32x4_ge_s (binary v128) + I32x4GeU => visit_i32x4_ge_u (binary v128) + I64x2Eq => visit_i64x2_eq (binary v128) + I64x2Ne => visit_i64x2_ne (binary v128) + I64x2LtS => visit_i64x2_lt_s (binary v128) + I64x2GtS => visit_i64x2_gt_s (binary v128) + I64x2LeS => visit_i64x2_le_s (binary v128) + I64x2GeS => visit_i64x2_ge_s (binary v128) + F32x4Eq => visit_f32x4_eq (binary v128f) + F32x4Ne => visit_f32x4_ne (binary v128f) + F32x4Lt => visit_f32x4_lt (binary v128f) + F32x4Gt => visit_f32x4_gt (binary v128f) + F32x4Le => visit_f32x4_le (binary v128f) + F32x4Ge => visit_f32x4_ge (binary v128f) + F64x2Eq => visit_f64x2_eq (binary v128f) + F64x2Ne => visit_f64x2_ne (binary v128f) + F64x2Lt => visit_f64x2_lt (binary v128f) + F64x2Gt => visit_f64x2_gt (binary v128f) + F64x2Le => visit_f64x2_le (binary v128f) + F64x2Ge => visit_f64x2_ge (binary v128f) + V128Not => visit_v128_not (unary v128) + V128And => visit_v128_and (binary v128) + V128AndNot => visit_v128_andnot (binary v128) + V128Or => visit_v128_or (binary v128) + V128Xor => visit_v128_xor (binary v128) + V128Bitselect => visit_v128_bitselect (ternary v128) + V128AnyTrue => visit_v128_any_true (test v128) + I8x16Abs => visit_i8x16_abs (unary v128) + I8x16Neg => visit_i8x16_neg (unary v128) + I8x16Popcnt => visit_i8x16_popcnt (unary v128) + I8x16AllTrue => visit_i8x16_all_true (test v128) + I8x16Bitmask => visit_i8x16_bitmask (test v128) + I8x16NarrowI16x8S => visit_i8x16_narrow_i16x8_s (binary v128) + I8x16NarrowI16x8U => visit_i8x16_narrow_i16x8_u (binary v128) + I8x16Shl => visit_i8x16_shl (shift v128) + I8x16ShrS => visit_i8x16_shr_s (shift v128) + I8x16ShrU => visit_i8x16_shr_u (shift v128) + I8x16Add => visit_i8x16_add (binary v128) + I8x16AddSatS => visit_i8x16_add_sat_s (binary v128) + I8x16AddSatU => visit_i8x16_add_sat_u (binary v128) + I8x16Sub => visit_i8x16_sub (binary v128) + I8x16SubSatS => visit_i8x16_sub_sat_s (binary v128) + I8x16SubSatU => visit_i8x16_sub_sat_u (binary v128) + I8x16MinS => visit_i8x16_min_s (binary v128) + I8x16MinU => visit_i8x16_min_u (binary v128) + I8x16MaxS => visit_i8x16_max_s (binary v128) + I8x16MaxU => visit_i8x16_max_u (binary v128) + I8x16AvgrU => visit_i8x16_avgr_u (binary v128) + I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s (unary v128) + I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u (unary v128) + I16x8Abs => visit_i16x8_abs (unary v128) + I16x8Neg => visit_i16x8_neg (unary v128) + I16x8Q15MulrSatS => visit_i16x8_q15mulr_sat_s (binary v128) + I16x8AllTrue => visit_i16x8_all_true (test v128) + I16x8Bitmask => visit_i16x8_bitmask (test v128) + I16x8NarrowI32x4S => visit_i16x8_narrow_i32x4_s (binary v128) + I16x8NarrowI32x4U => visit_i16x8_narrow_i32x4_u (binary v128) + I16x8ExtendLowI8x16S => visit_i16x8_extend_low_i8x16_s (unary v128) + I16x8ExtendHighI8x16S => visit_i16x8_extend_high_i8x16_s (unary v128) + I16x8ExtendLowI8x16U => visit_i16x8_extend_low_i8x16_u (unary v128) + I16x8ExtendHighI8x16U => visit_i16x8_extend_high_i8x16_u (unary v128) + I16x8Shl => visit_i16x8_shl (shift v128) + I16x8ShrS => visit_i16x8_shr_s (shift v128) + I16x8ShrU => visit_i16x8_shr_u (shift v128) + I16x8Add => visit_i16x8_add (binary v128) + I16x8AddSatS => visit_i16x8_add_sat_s (binary v128) + I16x8AddSatU => visit_i16x8_add_sat_u (binary v128) + I16x8Sub => visit_i16x8_sub (binary v128) + I16x8SubSatS => visit_i16x8_sub_sat_s (binary v128) + I16x8SubSatU => visit_i16x8_sub_sat_u (binary v128) + I16x8Mul => visit_i16x8_mul (binary v128) + I16x8MinS => visit_i16x8_min_s (binary v128) + I16x8MinU => visit_i16x8_min_u (binary v128) + I16x8MaxS => visit_i16x8_max_s (binary v128) + I16x8MaxU => visit_i16x8_max_u (binary v128) + I16x8AvgrU => visit_i16x8_avgr_u (binary v128) + I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s (binary v128) + I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s (binary v128) + I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u (binary v128) + I16x8ExtMulHighI8x16U => visit_i16x8_extmul_high_i8x16_u (binary v128) + I32x4ExtAddPairwiseI16x8S => visit_i32x4_extadd_pairwise_i16x8_s (unary v128) + I32x4ExtAddPairwiseI16x8U => visit_i32x4_extadd_pairwise_i16x8_u (unary v128) + I32x4Abs => visit_i32x4_abs (unary v128) + I32x4Neg => visit_i32x4_neg (unary v128) + I32x4AllTrue => visit_i32x4_all_true (test v128) + I32x4Bitmask => visit_i32x4_bitmask (test v128) + I32x4ExtendLowI16x8S => visit_i32x4_extend_low_i16x8_s (unary v128) + I32x4ExtendHighI16x8S => visit_i32x4_extend_high_i16x8_s (unary v128) + I32x4ExtendLowI16x8U => visit_i32x4_extend_low_i16x8_u (unary v128) + I32x4ExtendHighI16x8U => visit_i32x4_extend_high_i16x8_u (unary v128) + I32x4Shl => visit_i32x4_shl (shift v128) + I32x4ShrS => visit_i32x4_shr_s (shift v128) + I32x4ShrU => visit_i32x4_shr_u (shift v128) + I32x4Add => visit_i32x4_add (binary v128) + I32x4Sub => visit_i32x4_sub (binary v128) + I32x4Mul => visit_i32x4_mul (binary v128) + I32x4MinS => visit_i32x4_min_s (binary v128) + I32x4MinU => visit_i32x4_min_u (binary v128) + I32x4MaxS => visit_i32x4_max_s (binary v128) + I32x4MaxU => visit_i32x4_max_u (binary v128) + I32x4DotI16x8S => visit_i32x4_dot_i16x8_s (binary v128) + I32x4ExtMulLowI16x8S => visit_i32x4_extmul_low_i16x8_s (binary v128) + I32x4ExtMulHighI16x8S => visit_i32x4_extmul_high_i16x8_s (binary v128) + I32x4ExtMulLowI16x8U => visit_i32x4_extmul_low_i16x8_u (binary v128) + I32x4ExtMulHighI16x8U => visit_i32x4_extmul_high_i16x8_u (binary v128) + I64x2Abs => visit_i64x2_abs (unary v128) + I64x2Neg => visit_i64x2_neg (unary v128) + I64x2AllTrue => visit_i64x2_all_true (test v128) + I64x2Bitmask => visit_i64x2_bitmask (test v128) + I64x2ExtendLowI32x4S => visit_i64x2_extend_low_i32x4_s (unary v128) + I64x2ExtendHighI32x4S => visit_i64x2_extend_high_i32x4_s (unary v128) + I64x2ExtendLowI32x4U => visit_i64x2_extend_low_i32x4_u (unary v128) + I64x2ExtendHighI32x4U => visit_i64x2_extend_high_i32x4_u (unary v128) + I64x2Shl => visit_i64x2_shl (shift v128) + I64x2ShrS => visit_i64x2_shr_s (shift v128) + I64x2ShrU => visit_i64x2_shr_u (shift v128) + I64x2Add => visit_i64x2_add (binary v128) + I64x2Sub => visit_i64x2_sub (binary v128) + I64x2Mul => visit_i64x2_mul (binary v128) + I64x2ExtMulLowI32x4S => visit_i64x2_extmul_low_i32x4_s (binary v128) + I64x2ExtMulHighI32x4S => visit_i64x2_extmul_high_i32x4_s (binary v128) + I64x2ExtMulLowI32x4U => visit_i64x2_extmul_low_i32x4_u (binary v128) + I64x2ExtMulHighI32x4U => visit_i64x2_extmul_high_i32x4_u (binary v128) + F32x4Ceil => visit_f32x4_ceil (unary v128f) + F32x4Floor => visit_f32x4_floor (unary v128f) + F32x4Trunc => visit_f32x4_trunc (unary v128f) + F32x4Nearest => visit_f32x4_nearest (unary v128f) + F32x4Abs => visit_f32x4_abs (unary v128f) + F32x4Neg => visit_f32x4_neg (unary v128f) + F32x4Sqrt => visit_f32x4_sqrt (unary v128f) + F32x4Add => visit_f32x4_add (binary v128f) + F32x4Sub => visit_f32x4_sub (binary v128f) + F32x4Mul => visit_f32x4_mul (binary v128f) + F32x4Div => visit_f32x4_div (binary v128f) + F32x4Min => visit_f32x4_min (binary v128f) + F32x4Max => visit_f32x4_max (binary v128f) + F32x4PMin => visit_f32x4_pmin (binary v128f) + F32x4PMax => visit_f32x4_pmax (binary v128f) + F64x2Ceil => visit_f64x2_ceil (unary v128f) + F64x2Floor => visit_f64x2_floor (unary v128f) + F64x2Trunc => visit_f64x2_trunc (unary v128f) + F64x2Nearest => visit_f64x2_nearest (unary v128f) + F64x2Abs => visit_f64x2_abs (unary v128f) + F64x2Neg => visit_f64x2_neg (unary v128f) + F64x2Sqrt => visit_f64x2_sqrt (unary v128f) + F64x2Add => visit_f64x2_add (binary v128f) + F64x2Sub => visit_f64x2_sub (binary v128f) + F64x2Mul => visit_f64x2_mul (binary v128f) + F64x2Div => visit_f64x2_div (binary v128f) + F64x2Min => visit_f64x2_min (binary v128f) + F64x2Max => visit_f64x2_max (binary v128f) + F64x2PMin => visit_f64x2_pmin (binary v128f) + F64x2PMax => visit_f64x2_pmax (binary v128f) + I32x4TruncSatF32x4S => visit_i32x4_trunc_sat_f32x4_s (unary v128f) + I32x4TruncSatF32x4U => visit_i32x4_trunc_sat_f32x4_u (unary v128f) + F32x4ConvertI32x4S => visit_f32x4_convert_i32x4_s (unary v128f) + F32x4ConvertI32x4U => visit_f32x4_convert_i32x4_u (unary v128f) + I32x4TruncSatF64x2SZero => visit_i32x4_trunc_sat_f64x2_s_zero (unary v128f) + I32x4TruncSatF64x2UZero => visit_i32x4_trunc_sat_f64x2_u_zero (unary v128f) + F64x2ConvertLowI32x4S => visit_f64x2_convert_low_i32x4_s (unary v128f) + F64x2ConvertLowI32x4U => visit_f64x2_convert_low_i32x4_u (unary v128f) + F32x4DemoteF64x2Zero => visit_f32x4_demote_f64x2_zero (unary v128f) + F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 (unary v128f) + } + + // Relaxed SIMD operators + // https://github.com/WebAssembly/relaxed-simd + @relaxed_simd { + I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle (binary v128) + I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s (unary v128) + I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u (unary v128) + I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero (unary v128) + I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero (unary v128) + F32x4RelaxedMadd => visit_f32x4_relaxed_madd (ternary v128) + F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd (ternary v128) + F64x2RelaxedMadd => visit_f64x2_relaxed_madd (ternary v128) + F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd (ternary v128) + I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect (ternary v128) + I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect (ternary v128) + I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect (ternary v128) + I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect (ternary v128) + F32x4RelaxedMin => visit_f32x4_relaxed_min (binary v128) + F32x4RelaxedMax => visit_f32x4_relaxed_max (binary v128) + F64x2RelaxedMin => visit_f64x2_relaxed_min (binary v128) + F64x2RelaxedMax => visit_f64x2_relaxed_max (binary v128) + I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s (binary v128) + I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s (binary v128) + I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s (ternary v128) + } + + @exceptions { + TryTable { try_table: $crate::TryTable } => visit_try_table (arity try_table -> ~try_table) + Throw { tag_index: u32 } => visit_throw (arity tag -> 0) + ThrowRef => visit_throw_ref (arity 1 -> 0) + } + // Deprecated old instructions from the exceptions proposal + @legacy_exceptions { + Try { blockty: $crate::BlockType } => visit_try (arity block -> ~block) + Catch { tag_index: u32 } => visit_catch (arity ~end -> ~tag) + Rethrow { relative_depth: u32 } => visit_rethrow (arity 0 -> 0) + Delegate { relative_depth: u32 } => visit_delegate (arity ~end -> end) + CatchAll => visit_catch_all (arity ~end -> 0) + } + + // Also 0xFE prefixed operators + // shared-everything threads + // https://github.com/WebAssembly/shared-everything-threads + @shared_everything_threads { + GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get (arity 0 -> 1) + GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set (arity 1 -> 0) + GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add (unary atomic global) + GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub (unary atomic global) + GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and (unary atomic global) + GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or (unary atomic global) + GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor (unary atomic global) + GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg (arity 1 -> 1) + GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg (arity 2 -> 1) + TableAtomicGet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_get (arity 1 -> 1) + TableAtomicSet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_set (arity 2 -> 0) + TableAtomicRmwXchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_xchg (arity 2 -> 1) + TableAtomicRmwCmpxchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_cmpxchg (arity 3 -> 1) + StructAtomicGet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get (arity 1 -> 1) + StructAtomicGetS { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_s (arity 1 -> 1) + StructAtomicGetU { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_u (arity 1 -> 1) + StructAtomicSet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_set (arity 2 -> 0) + StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add (atomic rmw struct add) + StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub (atomic rmw struct sub) + StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and (atomic rmw struct and) + StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or (atomic rmw struct or) + StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor (atomic rmw struct xor) + StructAtomicRmwXchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xchg (arity 2 -> 1) + StructAtomicRmwCmpxchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_cmpxchg (arity 3 -> 1) + ArrayAtomicGet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get (arity 2 -> 1) + ArrayAtomicGetS { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_s (arity 2 -> 1) + ArrayAtomicGetU { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_u (arity 2 -> 1) + ArrayAtomicSet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_set (arity 3 -> 0) + ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add (atomic rmw array add) + ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub (atomic rmw array sub) + ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and (atomic rmw array and) + ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or (atomic rmw array or) + ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor (atomic rmw array xor) + ArrayAtomicRmwXchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xchg (arity 3 -> 1) + ArrayAtomicRmwCmpxchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_cmpxchg (arity 4 -> 1) + RefI31Shared => visit_ref_i31_shared (arity 1 -> 1) + } + + // Typed Function references + @function_references { + CallRef { type_index: u32 } => visit_call_ref (arity 1 type -> type) + ReturnCallRef { type_index: u32 } => visit_return_call_ref (arity 1 type -> 0) + RefAsNonNull => visit_ref_as_non_null (arity 1 -> 1) + BrOnNull { relative_depth: u32 } => visit_br_on_null (arity 1 br -> 1 br) + BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null (arity br -> br -1) + } + + // Stack switching + @stack_switching { + ContNew { cont_type_index: u32 } => visit_cont_new (arity 1 -> 1) + ContBind { argument_index: u32, result_index: u32 } => visit_cont_bind (arity type_diff 1 -> 1) + Suspend { tag_index: u32 } => visit_suspend (arity tag -> tag) + Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity 1 type -> type) + ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity 1 tag -> type) + Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity type -> ~switch) + } + + @wide_arithmetic { + I64Add128 => visit_i64_add128 (arity 4 -> 2) + I64Sub128 => visit_i64_sub128 (arity 4 -> 2) + I64MulWideS => visit_i64_mul_wide_s (arity 2 -> 2) + I64MulWideU => visit_i64_mul_wide_u (arity 2 -> 2) + } + } + }; +} + +/// Helper macro to define a `_for_each_non_simd_operator` which receives +/// the syntax of each instruction individually, but only the non-simd +/// operators. +macro_rules! define_for_each_non_simd_operator { + // Switch from `_for_each_operator_group` syntax to this macro's syntax to + // be a "tt muncher macro" + (@ $($t:tt)*) => {define_for_each_non_simd_operator!(filter [] @ $($t)*);}; + + // filter out simd/relaxed-simd proposals + (filter $filter:tt @simd $simd:tt $($rest:tt)*) => { + define_for_each_non_simd_operator!(filter $filter $($rest)*); + }; + (filter $filter:tt @relaxed_simd $simd:tt $($rest:tt)*) => { + define_for_each_non_simd_operator!(filter $filter $($rest)*); + }; + + // For all other proposals add in tokens where the `@proposal` is prepended + // before each instruction. + ( + filter [$($t:tt)*] + @$proposal:ident { + $( $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )* + } + $($rest:tt)* + ) => { + define_for_each_non_simd_operator!( + filter [ + $($t)* + $( @$proposal $op $({ $($arg: $argty),* })? => $visit ($($ann)*) )* + ] + $($rest)* + ); + }; + + // At the end the `$t` list here is how we want to define + // `_for_each_non_simd_operator`, so define the macro with these tokens. + (filter [$($t:tt)*]) => { + #[macro_export] + #[doc(hidden)] + macro_rules! _for_each_visit_operator_impl { + ($m:ident) => { + $m! { $($t)* } + } + } + + // When simd is disabled then this macro is additionally the + // `for_each_operator!` macro implementation + #[cfg(not(feature = "simd"))] + #[doc(hidden)] + pub use _for_each_visit_operator_impl as _for_each_operator_impl; + }; +} +_for_each_operator_group!(define_for_each_non_simd_operator); + +/// When the simd feature is enabled then `_for_each_operator_impl` is defined +/// to be the same as the above `define_for_each_non_simd_operator` macro except +/// with all proposals thrown in. +#[cfg(feature = "simd")] +macro_rules! define_for_each_operator_impl_with_simd { + ( + $( + @$proposal:ident { + $( $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )* + } + )* + ) => { + #[macro_export] + #[doc(hidden)] + macro_rules! _for_each_operator_impl { + ($m:ident) => { + $m! { + $( + $( + @$proposal $op $({$($arg: $argty),*})? => $visit ($($ann)*) + )* + )* + } + } + } + }; +} +#[cfg(feature = "simd")] +_for_each_operator_group!(define_for_each_operator_impl_with_simd); + +/// Helper macro to define the `_for_each_simd_operator_impl` macro. +/// +/// This is basically the same as `define_for_each_non_simd_operator` above +/// except that it's filtering on different proposals. +#[cfg(feature = "simd")] +macro_rules! define_for_each_simd_operator { + // Switch to "tt muncher" mode + (@ $($t:tt)*) => {define_for_each_simd_operator!(filter [] @ $($t)*);}; + + // Collect the `@simd` and `@relaxed_simd` proposals. + ( + filter [$($t:tt)*] + @simd { + $( $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )* + } + $($rest:tt)* + ) => { + define_for_each_simd_operator!( + filter [ + $($t)* + $( @simd $op $({ $($arg: $argty),* })? => $visit ($($ann)*) )* + ] + $($rest)* + ); + }; + ( + filter [$($t:tt)*] + @relaxed_simd { + $( $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )* + } + $($rest:tt)* + ) => { + define_for_each_simd_operator!( + filter [ + $($t)* + $( @relaxed_simd $op $({ $($arg: $argty),* })? => $visit ($($ann)*) )* + ] + $($rest)* + ); + }; + + // Skip all other proposals. + (filter $filter:tt @$proposal:ident $instrs:tt $($rest:tt)*) => { + define_for_each_simd_operator!(filter $filter $($rest)*); + }; + + // Base case to define the base macro. + (filter [$($t:tt)*]) => { + #[macro_export] + #[doc(hidden)] + macro_rules! _for_each_visit_simd_operator_impl { + ($m:ident) => { + $m! { $($t)* } + } + } + }; +} +#[cfg(feature = "simd")] +_for_each_operator_group!(define_for_each_simd_operator); + +/// Used to implement routines for the [`Operator`] enum. +/// /// A helper macro to conveniently iterate over all opcodes recognized by this /// crate. This can be used to work with either the [`Operator`] enumeration or /// the [`VisitOperator`] trait if your use case uniformly handles all operators @@ -65,7 +937,7 @@ mod prelude { /// /// This is an "iterator macro" where this macro is invoked with the name of /// another macro, and then that macro is invoked with the list of all -/// operators. An example invocation of this looks like: +/// operators. /// /// The list of specializable Wasm proposals is as follows: /// @@ -76,9 +948,9 @@ mod prelude { /// - `@sign_extension`: [Wasm `sign-extension-ops` proposal] /// - `@saturating_float_to_int`: [Wasm `non_trapping_float-to-int-conversions` proposal] /// - `@bulk_memory `:[Wasm `bulk-memory` proposal] -/// - `@threads`: [Wasm `threads` proposal] /// - `@simd`: [Wasm `simd` proposal] /// - `@relaxed_simd`: [Wasm `relaxed-simd` proposal] +/// - `@threads`: [Wasm `threads` proposal] /// - `@gc`: [Wasm `gc` proposal] /// - `@stack_switching`: [Wasm `stack-switching` proposal] /// - `@wide_arithmetic`: [Wasm `wide-arithmetic` proposal] @@ -101,15 +973,147 @@ mod prelude { /// [Wasm `bulk-memory` proposal]: /// https://github.com/WebAssembly/bulk-memory-operations /// +/// [Wasm `simd` proposal]: +/// https://github.com/webassembly/simd +/// +/// [Wasm `relaxed-simd` proposal]: +/// https://github.com/WebAssembly/relaxed-simd +/// /// [Wasm `threads` proposal]: /// https://github.com/webassembly/threads /// +/// [Wasm `gc` proposal]: +/// https://github.com/WebAssembly/gc +/// +/// [Wasm `stack-switching` proposal]: +/// https://github.com/WebAssembly/stack-switching +/// +/// [Wasm `wide-arithmetic` proposal]: +/// https://github.com/WebAssembly/wide-arithmetic +/// +/// ``` +/// fn do_nothing(op: &wasmparser::Operator) { +/// macro_rules! define_match_operator { +/// // The outer layer of repetition represents how all operators are +/// // provided to the macro at the same time. +/// // +/// // The `$proposal` identifier indicates the Wasm proposals from which +/// // the Wasm operator is originating. +/// // For example to specialize the macro match arm for Wasm SIMD proposal +/// // operators you could write `@simd` instead of `@$proposal:ident` to +/// // only catch those operators. +/// // +/// // The `$op` name is bound to the `Operator` variant name. The +/// // payload of the operator is optionally specified (the `$(...)?` +/// // clause) since not all instructions have payloads. Within the payload +/// // each argument is named and has its type specified. +/// // +/// // The `$visit` name is bound to the corresponding name in the +/// // `VisitOperator` trait that this corresponds to. +/// // +/// // The `$ann` annotations give information about the operator's type (e.g. binary i32 or arity 2 -> 1). +/// ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { +/// match op { +/// $( +/// wasmparser::Operator::$op $( { $($arg),* } )? => { +/// // do nothing for this example +/// } +/// )* +/// _ => unreachable!(), // required because `Operator` enum is non-exhaustive +/// } +/// } +/// } +/// wasmparser::for_each_operator!(define_match_operator); +/// } +/// ``` +/// +/// If you only wanted to visit the initial base set of wasm instructions, for +/// example, you could do: +/// +/// ``` +/// fn is_mvp_operator(op: &wasmparser::Operator) -> bool { +/// macro_rules! define_match_operator { +/// // delegate the macro invocation to sub-invocations of this macro to +/// // deal with each instruction on a case-by-case basis. +/// ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { +/// match op { +/// $( +/// wasmparser::Operator::$op $( { $($arg),* } )? => { +/// define_match_operator!(impl_one @$proposal) +/// } +/// )* +/// _ => unreachable!(), // required because `Operator` enum is non-exhaustive +/// } +/// }; +/// +/// (impl_one @mvp) => { true }; +/// (impl_one @$proposal:ident) => { false }; +/// } +/// wasmparser::for_each_operator!(define_match_operator) +/// } +/// ``` +#[doc(inline)] +pub use _for_each_operator_impl as for_each_operator; + +/// Used to implement the [`VisitOperator`] trait. +/// +/// A helper macro to conveniently iterate over all opcodes recognized by this +/// crate. This can be used to work with either the [`Operator`] enumeration or +/// the [`VisitOperator`] trait if your use case uniformly handles all operators +/// the same way. +/// +/// It is also possible to specialize handling of operators depending on the +/// Wasm proposal from which they are originating. +/// +/// This is an "iterator macro" where this macro is invoked with the name of +/// another macro, and then that macro is invoked with the list of all +/// operators. +/// +/// The list of specializable Wasm proposals is as follows: +/// +/// - `@mvp`: Denoting a Wasm operator from the initial Wasm MVP version. +/// - `@exceptions`: [Wasm `exception-handling` proposal] +/// - `@tail_call`: [Wasm `tail-calls` proposal] +/// - `@reference_types`: [Wasm `reference-types` proposal] +/// - `@sign_extension`: [Wasm `sign-extension-ops` proposal] +/// - `@saturating_float_to_int`: [Wasm `non_trapping_float-to-int-conversions` proposal] +/// - `@bulk_memory `:[Wasm `bulk-memory` proposal] +/// - `@threads`: [Wasm `threads` proposal] +/// - `@gc`: [Wasm `gc` proposal] +/// - `@stack_switching`: [Wasm `stack-switching` proposal] +/// - `@wide_arithmetic`: [Wasm `wide-arithmetic` proposal] +/// +/// Note that this macro does not iterate over the SIMD-related proposals. Those +/// are provided in [`VisitSimdOperator`] and [`for_each_visit_simd_operator`]. +/// This macro only handles non-SIMD related operators and so users wanting to +/// handle the SIMD-class of operators need to use that trait/macro as well. +/// +/// [Wasm `exception-handling` proposal]: +/// https://github.com/WebAssembly/exception-handling +/// +/// [Wasm `tail-calls` proposal]: +/// https://github.com/WebAssembly/tail-call +/// +/// [Wasm `reference-types` proposal]: +/// https://github.com/WebAssembly/reference-types +/// +/// [Wasm `sign-extension-ops` proposal]: +/// https://github.com/WebAssembly/sign-extension-ops +/// +/// [Wasm `non_trapping_float-to-int-conversions` proposal]: +/// https://github.com/WebAssembly/nontrapping-float-to-int-conversions +/// +/// [Wasm `bulk-memory` proposal]: +/// https://github.com/WebAssembly/bulk-memory-operations /// [Wasm `simd` proposal]: /// https://github.com/webassembly/simd /// /// [Wasm `relaxed-simd` proposal]: /// https://github.com/WebAssembly/relaxed-simd /// +/// [Wasm `threads` proposal]: +/// https://github.com/webassembly/threads +/// /// [Wasm `gc` proposal]: /// https://github.com/WebAssembly/gc /// @@ -153,7 +1157,7 @@ mod prelude { /// impl<'a> wasmparser::VisitOperator<'a> for VisitAndDoNothing { /// type Output = (); /// -/// wasmparser::for_each_operator!(define_visit_operator); +/// wasmparser::for_each_visit_operator!(define_visit_operator); /// } /// ``` /// @@ -203,687 +1207,35 @@ mod prelude { /// impl<'a> wasmparser::VisitOperator<'a> for VisitOnlyMvp { /// type Output = bool; /// -/// wasmparser::for_each_operator!(visit_only_mvp); -/// # wasmparser::for_each_operator!(visit_mvp); +/// wasmparser::for_each_visit_operator!(visit_only_mvp); +/// # wasmparser::for_each_visit_operator!(visit_mvp); /// /// // manually define `visit_*` for all MVP operators here /// } /// ``` -#[macro_export] -macro_rules! for_each_operator { - ($mac:ident) => { - $mac! { - @mvp Unreachable => visit_unreachable (arity 0 -> 0) - @mvp Nop => visit_nop (arity 0 -> 0) - @mvp Block { blockty: $crate::BlockType } => visit_block (arity block -> ~block) - @mvp Loop { blockty: $crate::BlockType } => visit_loop (arity block -> ~block) - @mvp If { blockty: $crate::BlockType } => visit_if (arity 1 block -> ~block) - @mvp Else => visit_else (arity ~end -> ~end) - @exceptions TryTable { try_table: $crate::TryTable } => visit_try_table (arity try_table -> ~try_table) - @exceptions Throw { tag_index: u32 } => visit_throw (arity tag -> 0) - @exceptions ThrowRef => visit_throw_ref (arity 1 -> 0) - // Deprecated old instructions from the exceptions proposal - @legacy_exceptions Try { blockty: $crate::BlockType } => visit_try (arity block -> ~block) - @legacy_exceptions Catch { tag_index: u32 } => visit_catch (arity ~end -> ~tag) - @legacy_exceptions Rethrow { relative_depth: u32 } => visit_rethrow (arity 0 -> 0) - @legacy_exceptions Delegate { relative_depth: u32 } => visit_delegate (arity ~end -> end) - @legacy_exceptions CatchAll => visit_catch_all (arity ~end -> 0) - @mvp End => visit_end (arity implicit_else ~end -> implicit_else end) - @mvp Br { relative_depth: u32 } => visit_br (arity br -> 0) - @mvp BrIf { relative_depth: u32 } => visit_br_if (arity 1 br -> br) - @mvp BrTable { targets: $crate::BrTable<'a> } => visit_br_table (arity 1 br_table -> 0) - @mvp Return => visit_return (arity ~ret -> 0) - @mvp Call { function_index: u32 } => visit_call (arity func -> func) - @mvp CallIndirect { type_index: u32, table_index: u32 } => visit_call_indirect (arity 1 type -> type) - @tail_call ReturnCall { function_index: u32 } => visit_return_call (arity func -> 0) - @tail_call ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect (arity 1 type -> 0) - @mvp Drop => visit_drop (arity 1 -> 0) - @mvp Select => visit_select (arity 3 -> 1) - @reference_types TypedSelect { ty: $crate::ValType } => visit_typed_select (arity 3 -> 1) - @mvp LocalGet { local_index: u32 } => visit_local_get (arity 0 -> 1) - @mvp LocalSet { local_index: u32 } => visit_local_set (arity 1 -> 0) - @mvp LocalTee { local_index: u32 } => visit_local_tee (arity 1 -> 1) - @mvp GlobalGet { global_index: u32 } => visit_global_get (arity 0 -> 1) - @mvp GlobalSet { global_index: u32 } => visit_global_set (arity 1 -> 0) - @mvp I32Load { memarg: $crate::MemArg } => visit_i32_load (load i32) - @mvp I64Load { memarg: $crate::MemArg } => visit_i64_load (load i64) - @mvp F32Load { memarg: $crate::MemArg } => visit_f32_load (load f32) - @mvp F64Load { memarg: $crate::MemArg } => visit_f64_load (load f64) - @mvp I32Load8S { memarg: $crate::MemArg } => visit_i32_load8_s (load i32) - @mvp I32Load8U { memarg: $crate::MemArg } => visit_i32_load8_u (load i32) - @mvp I32Load16S { memarg: $crate::MemArg } => visit_i32_load16_s (load i32) - @mvp I32Load16U { memarg: $crate::MemArg } => visit_i32_load16_u (load i32) - @mvp I64Load8S { memarg: $crate::MemArg } => visit_i64_load8_s (load i64) - @mvp I64Load8U { memarg: $crate::MemArg } => visit_i64_load8_u (load i64) - @mvp I64Load16S { memarg: $crate::MemArg } => visit_i64_load16_s (load i64) - @mvp I64Load16U { memarg: $crate::MemArg } => visit_i64_load16_u (load i64) - @mvp I64Load32S { memarg: $crate::MemArg } => visit_i64_load32_s (load i64) - @mvp I64Load32U { memarg: $crate::MemArg } => visit_i64_load32_u (load i64) - @mvp I32Store { memarg: $crate::MemArg } => visit_i32_store (store i32) - @mvp I64Store { memarg: $crate::MemArg } => visit_i64_store (store i64) - @mvp F32Store { memarg: $crate::MemArg } => visit_f32_store (store f32) - @mvp F64Store { memarg: $crate::MemArg } => visit_f64_store (store f64) - @mvp I32Store8 { memarg: $crate::MemArg } => visit_i32_store8 (store i32) - @mvp I32Store16 { memarg: $crate::MemArg } => visit_i32_store16 (store i32) - @mvp I64Store8 { memarg: $crate::MemArg } => visit_i64_store8 (store i64) - @mvp I64Store16 { memarg: $crate::MemArg } => visit_i64_store16 (store i64) - @mvp I64Store32 { memarg: $crate::MemArg } => visit_i64_store32 (store i64) - @mvp MemorySize { mem: u32 } => visit_memory_size (arity 0 -> 1) - @mvp MemoryGrow { mem: u32 } => visit_memory_grow (arity 1 -> 1) - @mvp I32Const { value: i32 } => visit_i32_const (push i32) - @mvp I64Const { value: i64 } => visit_i64_const (push i64) - @mvp F32Const { value: $crate::Ieee32 } => visit_f32_const (push f32) - @mvp F64Const { value: $crate::Ieee64 } => visit_f64_const (push f64) - @reference_types RefNull { hty: $crate::HeapType } => visit_ref_null (arity 0 -> 1) - @reference_types RefIsNull => visit_ref_is_null (arity 1 -> 1) - @reference_types RefFunc { function_index: u32 } => visit_ref_func (arity 0 -> 1) - @gc RefEq => visit_ref_eq (arity 2 -> 1) - @mvp I32Eqz => visit_i32_eqz (test i32) - @mvp I32Eq => visit_i32_eq (cmp i32) - @mvp I32Ne => visit_i32_ne (cmp i32) - @mvp I32LtS => visit_i32_lt_s (cmp i32) - @mvp I32LtU => visit_i32_lt_u (cmp i32) - @mvp I32GtS => visit_i32_gt_s (cmp i32) - @mvp I32GtU => visit_i32_gt_u (cmp i32) - @mvp I32LeS => visit_i32_le_s (cmp i32) - @mvp I32LeU => visit_i32_le_u (cmp i32) - @mvp I32GeS => visit_i32_ge_s (cmp i32) - @mvp I32GeU => visit_i32_ge_u (cmp i32) - @mvp I64Eqz => visit_i64_eqz (test i64) - @mvp I64Eq => visit_i64_eq (cmp i64) - @mvp I64Ne => visit_i64_ne (cmp i64) - @mvp I64LtS => visit_i64_lt_s (cmp i64) - @mvp I64LtU => visit_i64_lt_u (cmp i64) - @mvp I64GtS => visit_i64_gt_s (cmp i64) - @mvp I64GtU => visit_i64_gt_u (cmp i64) - @mvp I64LeS => visit_i64_le_s (cmp i64) - @mvp I64LeU => visit_i64_le_u (cmp i64) - @mvp I64GeS => visit_i64_ge_s (cmp i64) - @mvp I64GeU => visit_i64_ge_u (cmp i64) - @mvp F32Eq => visit_f32_eq (cmp f32) - @mvp F32Ne => visit_f32_ne (cmp f32) - @mvp F32Lt => visit_f32_lt (cmp f32) - @mvp F32Gt => visit_f32_gt (cmp f32) - @mvp F32Le => visit_f32_le (cmp f32) - @mvp F32Ge => visit_f32_ge (cmp f32) - @mvp F64Eq => visit_f64_eq (cmp f64) - @mvp F64Ne => visit_f64_ne (cmp f64) - @mvp F64Lt => visit_f64_lt (cmp f64) - @mvp F64Gt => visit_f64_gt (cmp f64) - @mvp F64Le => visit_f64_le (cmp f64) - @mvp F64Ge => visit_f64_ge (cmp f64) - @mvp I32Clz => visit_i32_clz (unary i32) - @mvp I32Ctz => visit_i32_ctz (unary i32) - @mvp I32Popcnt => visit_i32_popcnt (unary i32) - @mvp I32Add => visit_i32_add (binary i32) - @mvp I32Sub => visit_i32_sub (binary i32) - @mvp I32Mul => visit_i32_mul (binary i32) - @mvp I32DivS => visit_i32_div_s (binary i32) - @mvp I32DivU => visit_i32_div_u (binary i32) - @mvp I32RemS => visit_i32_rem_s (binary i32) - @mvp I32RemU => visit_i32_rem_u (binary i32) - @mvp I32And => visit_i32_and (binary i32) - @mvp I32Or => visit_i32_or (binary i32) - @mvp I32Xor => visit_i32_xor (binary i32) - @mvp I32Shl => visit_i32_shl (binary i32) - @mvp I32ShrS => visit_i32_shr_s (binary i32) - @mvp I32ShrU => visit_i32_shr_u (binary i32) - @mvp I32Rotl => visit_i32_rotl (binary i32) - @mvp I32Rotr => visit_i32_rotr (binary i32) - @mvp I64Clz => visit_i64_clz (unary i64) - @mvp I64Ctz => visit_i64_ctz (unary i64) - @mvp I64Popcnt => visit_i64_popcnt (unary i64) - @mvp I64Add => visit_i64_add (binary i64) - @mvp I64Sub => visit_i64_sub (binary i64) - @mvp I64Mul => visit_i64_mul (binary i64) - @mvp I64DivS => visit_i64_div_s (binary i64) - @mvp I64DivU => visit_i64_div_u (binary i64) - @mvp I64RemS => visit_i64_rem_s (binary i64) - @mvp I64RemU => visit_i64_rem_u (binary i64) - @mvp I64And => visit_i64_and (binary i64) - @mvp I64Or => visit_i64_or (binary i64) - @mvp I64Xor => visit_i64_xor (binary i64) - @mvp I64Shl => visit_i64_shl (binary i64) - @mvp I64ShrS => visit_i64_shr_s (binary i64) - @mvp I64ShrU => visit_i64_shr_u (binary i64) - @mvp I64Rotl => visit_i64_rotl (binary i64) - @mvp I64Rotr => visit_i64_rotr (binary i64) - @mvp F32Abs => visit_f32_abs (unary f32) - @mvp F32Neg => visit_f32_neg (unary f32) - @mvp F32Ceil => visit_f32_ceil (unary f32) - @mvp F32Floor => visit_f32_floor (unary f32) - @mvp F32Trunc => visit_f32_trunc (unary f32) - @mvp F32Nearest => visit_f32_nearest (unary f32) - @mvp F32Sqrt => visit_f32_sqrt (unary f32) - @mvp F32Add => visit_f32_add (binary f32) - @mvp F32Sub => visit_f32_sub (binary f32) - @mvp F32Mul => visit_f32_mul (binary f32) - @mvp F32Div => visit_f32_div (binary f32) - @mvp F32Min => visit_f32_min (binary f32) - @mvp F32Max => visit_f32_max (binary f32) - @mvp F32Copysign => visit_f32_copysign (binary f32) - @mvp F64Abs => visit_f64_abs (unary f64) - @mvp F64Neg => visit_f64_neg (unary f64) - @mvp F64Ceil => visit_f64_ceil (unary f64) - @mvp F64Floor => visit_f64_floor (unary f64) - @mvp F64Trunc => visit_f64_trunc (unary f64) - @mvp F64Nearest => visit_f64_nearest (unary f64) - @mvp F64Sqrt => visit_f64_sqrt (unary f64) - @mvp F64Add => visit_f64_add (binary f64) - @mvp F64Sub => visit_f64_sub (binary f64) - @mvp F64Mul => visit_f64_mul (binary f64) - @mvp F64Div => visit_f64_div (binary f64) - @mvp F64Min => visit_f64_min (binary f64) - @mvp F64Max => visit_f64_max (binary f64) - @mvp F64Copysign => visit_f64_copysign (binary f64) - @mvp I32WrapI64 => visit_i32_wrap_i64 (conversion i32 i64) - @mvp I32TruncF32S => visit_i32_trunc_f32_s (conversion i32 f32) - @mvp I32TruncF32U => visit_i32_trunc_f32_u (conversion i32 f32) - @mvp I32TruncF64S => visit_i32_trunc_f64_s (conversion i32 f64) - @mvp I32TruncF64U => visit_i32_trunc_f64_u (conversion i32 f64) - @mvp I64ExtendI32S => visit_i64_extend_i32_s (conversion i64 i32) - @mvp I64ExtendI32U => visit_i64_extend_i32_u (conversion i64 i32) - @mvp I64TruncF32S => visit_i64_trunc_f32_s (conversion i64 f32) - @mvp I64TruncF32U => visit_i64_trunc_f32_u (conversion i64 f32) - @mvp I64TruncF64S => visit_i64_trunc_f64_s (conversion i64 f64) - @mvp I64TruncF64U => visit_i64_trunc_f64_u (conversion i64 f64) - @mvp F32ConvertI32S => visit_f32_convert_i32_s (conversion f32 i32) - @mvp F32ConvertI32U => visit_f32_convert_i32_u (conversion f32 i32) - @mvp F32ConvertI64S => visit_f32_convert_i64_s (conversion f32 i64) - @mvp F32ConvertI64U => visit_f32_convert_i64_u (conversion f32 i64) - @mvp F32DemoteF64 => visit_f32_demote_f64 (conversion f32 f64) - @mvp F64ConvertI32S => visit_f64_convert_i32_s (conversion f64 i32) - @mvp F64ConvertI32U => visit_f64_convert_i32_u (conversion f64 i32) - @mvp F64ConvertI64S => visit_f64_convert_i64_s (conversion f64 i64) - @mvp F64ConvertI64U => visit_f64_convert_i64_u (conversion f64 i64) - @mvp F64PromoteF32 => visit_f64_promote_f32 (conversion f64 f32) - @mvp I32ReinterpretF32 => visit_i32_reinterpret_f32 (conversion i32 f32) - @mvp I64ReinterpretF64 => visit_i64_reinterpret_f64 (conversion i64 f64) - @mvp F32ReinterpretI32 => visit_f32_reinterpret_i32 (conversion f32 i32) - @mvp F64ReinterpretI64 => visit_f64_reinterpret_i64 (conversion f64 i64) - @sign_extension I32Extend8S => visit_i32_extend8_s (unary i32) - @sign_extension I32Extend16S => visit_i32_extend16_s (unary i32) - @sign_extension I64Extend8S => visit_i64_extend8_s (unary i64) - @sign_extension I64Extend16S => visit_i64_extend16_s (unary i64) - @sign_extension I64Extend32S => visit_i64_extend32_s (unary i64) +#[doc(inline)] +pub use _for_each_visit_operator_impl as for_each_visit_operator; - // 0xFB prefixed operators - // Garbage Collection - // http://github.com/WebAssembly/gc - @gc StructNew { struct_type_index: u32 } => visit_struct_new (arity type -> 1) - @gc StructNewDefault { struct_type_index: u32 } => visit_struct_new_default (arity 0 -> 1) - @gc StructGet { struct_type_index: u32, field_index: u32 } => visit_struct_get (arity 1 -> 1) - @gc StructGetS { struct_type_index: u32, field_index: u32 } => visit_struct_get_s (arity 1 -> 1) - @gc StructGetU { struct_type_index: u32, field_index: u32 } => visit_struct_get_u (arity 1 -> 1) - @gc StructSet { struct_type_index: u32, field_index: u32 } => visit_struct_set (arity 2 -> 0) - @gc ArrayNew { array_type_index: u32 } => visit_array_new (arity 2 -> 1) - @gc ArrayNewDefault { array_type_index: u32 } => visit_array_new_default (arity 1 -> 1) - @gc ArrayNewFixed { array_type_index: u32, array_size: u32 } => visit_array_new_fixed (arity size -> 1) - @gc ArrayNewData { array_type_index: u32, array_data_index: u32 } => visit_array_new_data (arity 2 -> 1) - @gc ArrayNewElem { array_type_index: u32, array_elem_index: u32 } => visit_array_new_elem (arity 2 -> 1) - @gc ArrayGet { array_type_index: u32 } => visit_array_get (arity 2 -> 1) - @gc ArrayGetS { array_type_index: u32 } => visit_array_get_s (arity 2 -> 1) - @gc ArrayGetU { array_type_index: u32 } => visit_array_get_u (arity 2 -> 1) - @gc ArraySet { array_type_index: u32 } => visit_array_set (arity 3 -> 0) - @gc ArrayLen => visit_array_len (arity 1 -> 1) - @gc ArrayFill { array_type_index: u32 } => visit_array_fill (arity 4 -> 0) - @gc ArrayCopy { array_type_index_dst: u32, array_type_index_src: u32 } => visit_array_copy (arity 5 -> 0) - @gc ArrayInitData { array_type_index: u32, array_data_index: u32 } => visit_array_init_data (arity 4 -> 0) - @gc ArrayInitElem { array_type_index: u32, array_elem_index: u32 } => visit_array_init_elem (arity 4 -> 0) - @gc RefTestNonNull { hty: $crate::HeapType } => visit_ref_test_non_null (arity 1 -> 1) - @gc RefTestNullable { hty: $crate::HeapType } => visit_ref_test_nullable (arity 1 -> 1) - @gc RefCastNonNull { hty: $crate::HeapType } => visit_ref_cast_non_null (arity 1 -> 1) - @gc RefCastNullable { hty: $crate::HeapType } => visit_ref_cast_nullable (arity 1 -> 1) - @gc BrOnCast { - relative_depth: u32, - from_ref_type: $crate::RefType, - to_ref_type: $crate::RefType - } => visit_br_on_cast (arity br -> br) - @gc BrOnCastFail { - relative_depth: u32, - from_ref_type: $crate::RefType, - to_ref_type: $crate::RefType - } => visit_br_on_cast_fail (arity br -> br) - @gc AnyConvertExtern => visit_any_convert_extern (arity 1 -> 1) - @gc ExternConvertAny => visit_extern_convert_any (arity 1 -> 1) - @gc RefI31 => visit_ref_i31 (arity 1 -> 1) - @gc I31GetS => visit_i31_get_s (arity 1 -> 1) - @gc I31GetU => visit_i31_get_u (arity 1 -> 1) - - // 0xFC operators - // Non-trapping Float-to-int Conversions - // https://github.com/WebAssembly/nontrapping-float-to-int-conversions - @saturating_float_to_int I32TruncSatF32S => visit_i32_trunc_sat_f32_s (conversion i32 f32) - @saturating_float_to_int I32TruncSatF32U => visit_i32_trunc_sat_f32_u (conversion i32 f32) - @saturating_float_to_int I32TruncSatF64S => visit_i32_trunc_sat_f64_s (conversion i32 f64) - @saturating_float_to_int I32TruncSatF64U => visit_i32_trunc_sat_f64_u (conversion i32 f64) - @saturating_float_to_int I64TruncSatF32S => visit_i64_trunc_sat_f32_s (conversion i64 f32) - @saturating_float_to_int I64TruncSatF32U => visit_i64_trunc_sat_f32_u (conversion i64 f32) - @saturating_float_to_int I64TruncSatF64S => visit_i64_trunc_sat_f64_s (conversion i64 f64) - @saturating_float_to_int I64TruncSatF64U => visit_i64_trunc_sat_f64_u (conversion i64 f64) - - // 0xFC prefixed operators - // bulk memory operations - // https://github.com/WebAssembly/bulk-memory-operations - @bulk_memory MemoryInit { data_index: u32, mem: u32 } => visit_memory_init (arity 3 -> 0) - @bulk_memory DataDrop { data_index: u32 } => visit_data_drop (arity 0 -> 0) - @bulk_memory MemoryCopy { dst_mem: u32, src_mem: u32 } => visit_memory_copy (arity 3 -> 0) - @bulk_memory MemoryFill { mem: u32 } => visit_memory_fill (arity 3 -> 0) - @bulk_memory TableInit { elem_index: u32, table: u32 } => visit_table_init (arity 3 -> 0) - @bulk_memory ElemDrop { elem_index: u32 } => visit_elem_drop (arity 0 -> 0) - @bulk_memory TableCopy { dst_table: u32, src_table: u32 } => visit_table_copy (arity 3 -> 0) - - // 0xFC prefixed operators - // reference-types - // https://github.com/WebAssembly/reference-types - @reference_types TableFill { table: u32 } => visit_table_fill (arity 3 -> 0) - @reference_types TableGet { table: u32 } => visit_table_get (arity 1 -> 1) - @reference_types TableSet { table: u32 } => visit_table_set (arity 2 -> 0) - @reference_types TableGrow { table: u32 } => visit_table_grow (arity 2 -> 1) - @reference_types TableSize { table: u32 } => visit_table_size (arity 0 -> 1) - - // OxFC prefixed operators - // memory control (experimental) - // https://github.com/WebAssembly/design/issues/1439 - @memory_control MemoryDiscard { mem: u32 } => visit_memory_discard (arity 2 -> 0) - - // 0xFE prefixed operators - // threads - // https://github.com/WebAssembly/threads - @threads MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify (atomic rmw i32) - @threads MemoryAtomicWait32 { memarg: $crate::MemArg } => visit_memory_atomic_wait32 (arity 3 -> 1) - @threads MemoryAtomicWait64 { memarg: $crate::MemArg } => visit_memory_atomic_wait64 (arity 3 -> 1) - @threads AtomicFence => visit_atomic_fence (arity 0 -> 0) - @threads I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load (load atomic i32) - @threads I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load (load atomic i64) - @threads I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u (load atomic i32) - @threads I32AtomicLoad16U { memarg: $crate::MemArg } => visit_i32_atomic_load16_u (load atomic i32) - @threads I64AtomicLoad8U { memarg: $crate::MemArg } => visit_i64_atomic_load8_u (load atomic i64) - @threads I64AtomicLoad16U { memarg: $crate::MemArg } => visit_i64_atomic_load16_u (load atomic i64) - @threads I64AtomicLoad32U { memarg: $crate::MemArg } => visit_i64_atomic_load32_u (load atomic i64) - @threads I32AtomicStore { memarg: $crate::MemArg } => visit_i32_atomic_store (store atomic i32) - @threads I64AtomicStore { memarg: $crate::MemArg } => visit_i64_atomic_store (store atomic i64) - @threads I32AtomicStore8 { memarg: $crate::MemArg } => visit_i32_atomic_store8 (store atomic i32) - @threads I32AtomicStore16 { memarg: $crate::MemArg } => visit_i32_atomic_store16 (store atomic i32) - @threads I64AtomicStore8 { memarg: $crate::MemArg } => visit_i64_atomic_store8 (store atomic i64) - @threads I64AtomicStore16 { memarg: $crate::MemArg } => visit_i64_atomic_store16 (store atomic i64) - @threads I64AtomicStore32 { memarg: $crate::MemArg } => visit_i64_atomic_store32 (store atomic i64) - @threads I32AtomicRmwAdd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_add (atomic rmw i32) - @threads I64AtomicRmwAdd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_add (atomic rmw i64) - @threads I32AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_add_u (atomic rmw i32) - @threads I32AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_add_u (atomic rmw i32) - @threads I64AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_add_u (atomic rmw i64) - @threads I64AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_add_u (atomic rmw i64) - @threads I64AtomicRmw32AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_add_u (atomic rmw i64) - @threads I32AtomicRmwSub { memarg: $crate::MemArg } => visit_i32_atomic_rmw_sub (atomic rmw i32) - @threads I64AtomicRmwSub { memarg: $crate::MemArg } => visit_i64_atomic_rmw_sub (atomic rmw i64) - @threads I32AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_sub_u (atomic rmw i32) - @threads I32AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_sub_u (atomic rmw i32) - @threads I64AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_sub_u (atomic rmw i64) - @threads I64AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_sub_u (atomic rmw i64) - @threads I64AtomicRmw32SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_sub_u (atomic rmw i64) - @threads I32AtomicRmwAnd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_and (atomic rmw i32) - @threads I64AtomicRmwAnd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_and (atomic rmw i64) - @threads I32AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_and_u (atomic rmw i32) - @threads I32AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_and_u (atomic rmw i32) - @threads I64AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_and_u (atomic rmw i64) - @threads I64AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_and_u (atomic rmw i64) - @threads I64AtomicRmw32AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_and_u (atomic rmw i64) - @threads I32AtomicRmwOr { memarg: $crate::MemArg } => visit_i32_atomic_rmw_or (atomic rmw i32) - @threads I64AtomicRmwOr { memarg: $crate::MemArg } => visit_i64_atomic_rmw_or (atomic rmw i64) - @threads I32AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_or_u (atomic rmw i32) - @threads I32AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_or_u (atomic rmw i32) - @threads I64AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_or_u (atomic rmw i64) - @threads I64AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_or_u (atomic rmw i64) - @threads I64AtomicRmw32OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_or_u (atomic rmw i64) - @threads I32AtomicRmwXor { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xor (atomic rmw i32) - @threads I64AtomicRmwXor { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xor (atomic rmw i64) - @threads I32AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xor_u (atomic rmw i32) - @threads I32AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xor_u (atomic rmw i32) - @threads I64AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xor_u (atomic rmw i64) - @threads I64AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xor_u (atomic rmw i64) - @threads I64AtomicRmw32XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xor_u (atomic rmw i64) - @threads I32AtomicRmwXchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xchg (atomic rmw i32) - @threads I64AtomicRmwXchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xchg (atomic rmw i64) - @threads I32AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xchg_u (atomic rmw i32) - @threads I32AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xchg_u (atomic rmw i32) - @threads I64AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xchg_u (atomic rmw i64) - @threads I64AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xchg_u (atomic rmw i64) - @threads I64AtomicRmw32XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xchg_u (atomic rmw i64) - @threads I32AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_cmpxchg (atomic cmpxchg i32) - @threads I64AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_cmpxchg (atomic cmpxchg i64) - @threads I32AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_cmpxchg_u (atomic cmpxchg i32) - @threads I32AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_cmpxchg_u (atomic cmpxchg i32) - @threads I64AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_cmpxchg_u (atomic cmpxchg i64) - @threads I64AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_cmpxchg_u (atomic cmpxchg i64) - @threads I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u (atomic cmpxchg i64) - - // Also 0xFE prefixed operators - // shared-everything threads - // https://github.com/WebAssembly/shared-everything-threads - @shared_everything_threads GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get (arity 0 -> 1) - @shared_everything_threads GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set (arity 1 -> 0) - @shared_everything_threads GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add (unary atomic global) - @shared_everything_threads GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub (unary atomic global) - @shared_everything_threads GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and (unary atomic global) - @shared_everything_threads GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or (unary atomic global) - @shared_everything_threads GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor (unary atomic global) - @shared_everything_threads GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg (arity 1 -> 1) - @shared_everything_threads GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg (arity 2 -> 1) - @shared_everything_threads TableAtomicGet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_get (arity 1 -> 1) - @shared_everything_threads TableAtomicSet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_set (arity 2 -> 0) - @shared_everything_threads TableAtomicRmwXchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_xchg (arity 2 -> 1) - @shared_everything_threads TableAtomicRmwCmpxchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_cmpxchg (arity 3 -> 1) - @shared_everything_threads StructAtomicGet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get (arity 1 -> 1) - @shared_everything_threads StructAtomicGetS { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_s (arity 1 -> 1) - @shared_everything_threads StructAtomicGetU { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_u (arity 1 -> 1) - @shared_everything_threads StructAtomicSet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_set (arity 2 -> 0) - @shared_everything_threads StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add (atomic rmw struct add) - @shared_everything_threads StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub (atomic rmw struct sub) - @shared_everything_threads StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and (atomic rmw struct and) - @shared_everything_threads StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or (atomic rmw struct or) - @shared_everything_threads StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor (atomic rmw struct xor) - @shared_everything_threads StructAtomicRmwXchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xchg (arity 2 -> 1) - @shared_everything_threads StructAtomicRmwCmpxchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_cmpxchg (arity 3 -> 1) - @shared_everything_threads ArrayAtomicGet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get (arity 2 -> 1) - @shared_everything_threads ArrayAtomicGetS { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_s (arity 2 -> 1) - @shared_everything_threads ArrayAtomicGetU { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_u (arity 2 -> 1) - @shared_everything_threads ArrayAtomicSet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_set (arity 3 -> 0) - @shared_everything_threads ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add (atomic rmw array add) - @shared_everything_threads ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub (atomic rmw array sub) - @shared_everything_threads ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and (atomic rmw array and) - @shared_everything_threads ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or (atomic rmw array or) - @shared_everything_threads ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor (atomic rmw array xor) - @shared_everything_threads ArrayAtomicRmwXchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xchg (arity 3 -> 1) - @shared_everything_threads ArrayAtomicRmwCmpxchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_cmpxchg (arity 4 -> 1) - @shared_everything_threads RefI31Shared => visit_ref_i31_shared (arity 1 -> 1) - - // 0xFD operators - // 128-bit SIMD - // - https://github.com/webassembly/simd - // - https://webassembly.github.io/simd/core/binary/instructions.html - @simd V128Load { memarg: $crate::MemArg } => visit_v128_load (load v128) - @simd V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s (load v128) - @simd V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u (load v128) - @simd V128Load16x4S { memarg: $crate::MemArg } => visit_v128_load16x4_s (load v128) - @simd V128Load16x4U { memarg: $crate::MemArg } => visit_v128_load16x4_u (load v128) - @simd V128Load32x2S { memarg: $crate::MemArg } => visit_v128_load32x2_s (load v128) - @simd V128Load32x2U { memarg: $crate::MemArg } => visit_v128_load32x2_u (load v128) - @simd V128Load8Splat { memarg: $crate::MemArg } => visit_v128_load8_splat (load v128) - @simd V128Load16Splat { memarg: $crate::MemArg } => visit_v128_load16_splat (load v128) - @simd V128Load32Splat { memarg: $crate::MemArg } => visit_v128_load32_splat (load v128) - @simd V128Load64Splat { memarg: $crate::MemArg } => visit_v128_load64_splat (load v128) - @simd V128Load32Zero { memarg: $crate::MemArg } => visit_v128_load32_zero (load v128) - @simd V128Load64Zero { memarg: $crate::MemArg } => visit_v128_load64_zero (load v128) - @simd V128Store { memarg: $crate::MemArg } => visit_v128_store (store v128) - @simd V128Load8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load8_lane (load lane 16) - @simd V128Load16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load16_lane (load lane 8) - @simd V128Load32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load32_lane (load lane 4) - @simd V128Load64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load64_lane (load lane 2) - @simd V128Store8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store8_lane (store lane 16) - @simd V128Store16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store16_lane (store lane 8) - @simd V128Store32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store32_lane (store lane 4) - @simd V128Store64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store64_lane (store lane 2) - @simd V128Const { value: $crate::V128 } => visit_v128_const (push v128) - @simd I8x16Shuffle { lanes: [u8; 16] } => visit_i8x16_shuffle (arity 2 -> 1) - @simd I8x16ExtractLaneS { lane: u8 } => visit_i8x16_extract_lane_s (extract i32 16) - @simd I8x16ExtractLaneU { lane: u8 } => visit_i8x16_extract_lane_u (extract i32 16) - @simd I8x16ReplaceLane { lane: u8 } => visit_i8x16_replace_lane (replace i32 16) - @simd I16x8ExtractLaneS { lane: u8 } => visit_i16x8_extract_lane_s (extract i32 8) - @simd I16x8ExtractLaneU { lane: u8 } => visit_i16x8_extract_lane_u (extract i32 8) - @simd I16x8ReplaceLane { lane: u8 } => visit_i16x8_replace_lane (replace i32 8) - @simd I32x4ExtractLane { lane: u8 } => visit_i32x4_extract_lane (extract i32 4) - @simd I32x4ReplaceLane { lane: u8 } => visit_i32x4_replace_lane (replace i32 4) - @simd I64x2ExtractLane { lane: u8 } => visit_i64x2_extract_lane (extract i64 2) - @simd I64x2ReplaceLane { lane: u8 } => visit_i64x2_replace_lane (replace i64 2) - @simd F32x4ExtractLane { lane: u8 } => visit_f32x4_extract_lane (extract f32 4) - @simd F32x4ReplaceLane { lane: u8 } => visit_f32x4_replace_lane (replace f32 4) - @simd F64x2ExtractLane { lane: u8 } => visit_f64x2_extract_lane (extract f64 2) - @simd F64x2ReplaceLane { lane: u8 } => visit_f64x2_replace_lane (replace f64 2) - @simd I8x16Swizzle => visit_i8x16_swizzle (binary v128) - @simd I8x16Splat => visit_i8x16_splat (splat i32) - @simd I16x8Splat => visit_i16x8_splat (splat i32) - @simd I32x4Splat => visit_i32x4_splat (splat i32) - @simd I64x2Splat => visit_i64x2_splat (splat i64) - @simd F32x4Splat => visit_f32x4_splat (splat f32) - @simd F64x2Splat => visit_f64x2_splat (splat f64) - @simd I8x16Eq => visit_i8x16_eq (binary v128) - @simd I8x16Ne => visit_i8x16_ne (binary v128) - @simd I8x16LtS => visit_i8x16_lt_s (binary v128) - @simd I8x16LtU => visit_i8x16_lt_u (binary v128) - @simd I8x16GtS => visit_i8x16_gt_s (binary v128) - @simd I8x16GtU => visit_i8x16_gt_u (binary v128) - @simd I8x16LeS => visit_i8x16_le_s (binary v128) - @simd I8x16LeU => visit_i8x16_le_u (binary v128) - @simd I8x16GeS => visit_i8x16_ge_s (binary v128) - @simd I8x16GeU => visit_i8x16_ge_u (binary v128) - @simd I16x8Eq => visit_i16x8_eq (binary v128) - @simd I16x8Ne => visit_i16x8_ne (binary v128) - @simd I16x8LtS => visit_i16x8_lt_s (binary v128) - @simd I16x8LtU => visit_i16x8_lt_u (binary v128) - @simd I16x8GtS => visit_i16x8_gt_s (binary v128) - @simd I16x8GtU => visit_i16x8_gt_u (binary v128) - @simd I16x8LeS => visit_i16x8_le_s (binary v128) - @simd I16x8LeU => visit_i16x8_le_u (binary v128) - @simd I16x8GeS => visit_i16x8_ge_s (binary v128) - @simd I16x8GeU => visit_i16x8_ge_u (binary v128) - @simd I32x4Eq => visit_i32x4_eq (binary v128) - @simd I32x4Ne => visit_i32x4_ne (binary v128) - @simd I32x4LtS => visit_i32x4_lt_s (binary v128) - @simd I32x4LtU => visit_i32x4_lt_u (binary v128) - @simd I32x4GtS => visit_i32x4_gt_s (binary v128) - @simd I32x4GtU => visit_i32x4_gt_u (binary v128) - @simd I32x4LeS => visit_i32x4_le_s (binary v128) - @simd I32x4LeU => visit_i32x4_le_u (binary v128) - @simd I32x4GeS => visit_i32x4_ge_s (binary v128) - @simd I32x4GeU => visit_i32x4_ge_u (binary v128) - @simd I64x2Eq => visit_i64x2_eq (binary v128) - @simd I64x2Ne => visit_i64x2_ne (binary v128) - @simd I64x2LtS => visit_i64x2_lt_s (binary v128) - @simd I64x2GtS => visit_i64x2_gt_s (binary v128) - @simd I64x2LeS => visit_i64x2_le_s (binary v128) - @simd I64x2GeS => visit_i64x2_ge_s (binary v128) - @simd F32x4Eq => visit_f32x4_eq (binary v128f) - @simd F32x4Ne => visit_f32x4_ne (binary v128f) - @simd F32x4Lt => visit_f32x4_lt (binary v128f) - @simd F32x4Gt => visit_f32x4_gt (binary v128f) - @simd F32x4Le => visit_f32x4_le (binary v128f) - @simd F32x4Ge => visit_f32x4_ge (binary v128f) - @simd F64x2Eq => visit_f64x2_eq (binary v128f) - @simd F64x2Ne => visit_f64x2_ne (binary v128f) - @simd F64x2Lt => visit_f64x2_lt (binary v128f) - @simd F64x2Gt => visit_f64x2_gt (binary v128f) - @simd F64x2Le => visit_f64x2_le (binary v128f) - @simd F64x2Ge => visit_f64x2_ge (binary v128f) - @simd V128Not => visit_v128_not (unary v128) - @simd V128And => visit_v128_and (binary v128) - @simd V128AndNot => visit_v128_andnot (binary v128) - @simd V128Or => visit_v128_or (binary v128) - @simd V128Xor => visit_v128_xor (binary v128) - @simd V128Bitselect => visit_v128_bitselect (ternary v128) - @simd V128AnyTrue => visit_v128_any_true (test v128) - @simd I8x16Abs => visit_i8x16_abs (unary v128) - @simd I8x16Neg => visit_i8x16_neg (unary v128) - @simd I8x16Popcnt => visit_i8x16_popcnt (unary v128) - @simd I8x16AllTrue => visit_i8x16_all_true (test v128) - @simd I8x16Bitmask => visit_i8x16_bitmask (test v128) - @simd I8x16NarrowI16x8S => visit_i8x16_narrow_i16x8_s (binary v128) - @simd I8x16NarrowI16x8U => visit_i8x16_narrow_i16x8_u (binary v128) - @simd I8x16Shl => visit_i8x16_shl (shift v128) - @simd I8x16ShrS => visit_i8x16_shr_s (shift v128) - @simd I8x16ShrU => visit_i8x16_shr_u (shift v128) - @simd I8x16Add => visit_i8x16_add (binary v128) - @simd I8x16AddSatS => visit_i8x16_add_sat_s (binary v128) - @simd I8x16AddSatU => visit_i8x16_add_sat_u (binary v128) - @simd I8x16Sub => visit_i8x16_sub (binary v128) - @simd I8x16SubSatS => visit_i8x16_sub_sat_s (binary v128) - @simd I8x16SubSatU => visit_i8x16_sub_sat_u (binary v128) - @simd I8x16MinS => visit_i8x16_min_s (binary v128) - @simd I8x16MinU => visit_i8x16_min_u (binary v128) - @simd I8x16MaxS => visit_i8x16_max_s (binary v128) - @simd I8x16MaxU => visit_i8x16_max_u (binary v128) - @simd I8x16AvgrU => visit_i8x16_avgr_u (binary v128) - @simd I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s (unary v128) - @simd I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u (unary v128) - @simd I16x8Abs => visit_i16x8_abs (unary v128) - @simd I16x8Neg => visit_i16x8_neg (unary v128) - @simd I16x8Q15MulrSatS => visit_i16x8_q15mulr_sat_s (binary v128) - @simd I16x8AllTrue => visit_i16x8_all_true (test v128) - @simd I16x8Bitmask => visit_i16x8_bitmask (test v128) - @simd I16x8NarrowI32x4S => visit_i16x8_narrow_i32x4_s (binary v128) - @simd I16x8NarrowI32x4U => visit_i16x8_narrow_i32x4_u (binary v128) - @simd I16x8ExtendLowI8x16S => visit_i16x8_extend_low_i8x16_s (unary v128) - @simd I16x8ExtendHighI8x16S => visit_i16x8_extend_high_i8x16_s (unary v128) - @simd I16x8ExtendLowI8x16U => visit_i16x8_extend_low_i8x16_u (unary v128) - @simd I16x8ExtendHighI8x16U => visit_i16x8_extend_high_i8x16_u (unary v128) - @simd I16x8Shl => visit_i16x8_shl (shift v128) - @simd I16x8ShrS => visit_i16x8_shr_s (shift v128) - @simd I16x8ShrU => visit_i16x8_shr_u (shift v128) - @simd I16x8Add => visit_i16x8_add (binary v128) - @simd I16x8AddSatS => visit_i16x8_add_sat_s (binary v128) - @simd I16x8AddSatU => visit_i16x8_add_sat_u (binary v128) - @simd I16x8Sub => visit_i16x8_sub (binary v128) - @simd I16x8SubSatS => visit_i16x8_sub_sat_s (binary v128) - @simd I16x8SubSatU => visit_i16x8_sub_sat_u (binary v128) - @simd I16x8Mul => visit_i16x8_mul (binary v128) - @simd I16x8MinS => visit_i16x8_min_s (binary v128) - @simd I16x8MinU => visit_i16x8_min_u (binary v128) - @simd I16x8MaxS => visit_i16x8_max_s (binary v128) - @simd I16x8MaxU => visit_i16x8_max_u (binary v128) - @simd I16x8AvgrU => visit_i16x8_avgr_u (binary v128) - @simd I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s (binary v128) - @simd I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s (binary v128) - @simd I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u (binary v128) - @simd I16x8ExtMulHighI8x16U => visit_i16x8_extmul_high_i8x16_u (binary v128) - @simd I32x4ExtAddPairwiseI16x8S => visit_i32x4_extadd_pairwise_i16x8_s (unary v128) - @simd I32x4ExtAddPairwiseI16x8U => visit_i32x4_extadd_pairwise_i16x8_u (unary v128) - @simd I32x4Abs => visit_i32x4_abs (unary v128) - @simd I32x4Neg => visit_i32x4_neg (unary v128) - @simd I32x4AllTrue => visit_i32x4_all_true (test v128) - @simd I32x4Bitmask => visit_i32x4_bitmask (test v128) - @simd I32x4ExtendLowI16x8S => visit_i32x4_extend_low_i16x8_s (unary v128) - @simd I32x4ExtendHighI16x8S => visit_i32x4_extend_high_i16x8_s (unary v128) - @simd I32x4ExtendLowI16x8U => visit_i32x4_extend_low_i16x8_u (unary v128) - @simd I32x4ExtendHighI16x8U => visit_i32x4_extend_high_i16x8_u (unary v128) - @simd I32x4Shl => visit_i32x4_shl (shift v128) - @simd I32x4ShrS => visit_i32x4_shr_s (shift v128) - @simd I32x4ShrU => visit_i32x4_shr_u (shift v128) - @simd I32x4Add => visit_i32x4_add (binary v128) - @simd I32x4Sub => visit_i32x4_sub (binary v128) - @simd I32x4Mul => visit_i32x4_mul (binary v128) - @simd I32x4MinS => visit_i32x4_min_s (binary v128) - @simd I32x4MinU => visit_i32x4_min_u (binary v128) - @simd I32x4MaxS => visit_i32x4_max_s (binary v128) - @simd I32x4MaxU => visit_i32x4_max_u (binary v128) - @simd I32x4DotI16x8S => visit_i32x4_dot_i16x8_s (binary v128) - @simd I32x4ExtMulLowI16x8S => visit_i32x4_extmul_low_i16x8_s (binary v128) - @simd I32x4ExtMulHighI16x8S => visit_i32x4_extmul_high_i16x8_s (binary v128) - @simd I32x4ExtMulLowI16x8U => visit_i32x4_extmul_low_i16x8_u (binary v128) - @simd I32x4ExtMulHighI16x8U => visit_i32x4_extmul_high_i16x8_u (binary v128) - @simd I64x2Abs => visit_i64x2_abs (unary v128) - @simd I64x2Neg => visit_i64x2_neg (unary v128) - @simd I64x2AllTrue => visit_i64x2_all_true (test v128) - @simd I64x2Bitmask => visit_i64x2_bitmask (test v128) - @simd I64x2ExtendLowI32x4S => visit_i64x2_extend_low_i32x4_s (unary v128) - @simd I64x2ExtendHighI32x4S => visit_i64x2_extend_high_i32x4_s (unary v128) - @simd I64x2ExtendLowI32x4U => visit_i64x2_extend_low_i32x4_u (unary v128) - @simd I64x2ExtendHighI32x4U => visit_i64x2_extend_high_i32x4_u (unary v128) - @simd I64x2Shl => visit_i64x2_shl (shift v128) - @simd I64x2ShrS => visit_i64x2_shr_s (shift v128) - @simd I64x2ShrU => visit_i64x2_shr_u (shift v128) - @simd I64x2Add => visit_i64x2_add (binary v128) - @simd I64x2Sub => visit_i64x2_sub (binary v128) - @simd I64x2Mul => visit_i64x2_mul (binary v128) - @simd I64x2ExtMulLowI32x4S => visit_i64x2_extmul_low_i32x4_s (binary v128) - @simd I64x2ExtMulHighI32x4S => visit_i64x2_extmul_high_i32x4_s (binary v128) - @simd I64x2ExtMulLowI32x4U => visit_i64x2_extmul_low_i32x4_u (binary v128) - @simd I64x2ExtMulHighI32x4U => visit_i64x2_extmul_high_i32x4_u (binary v128) - @simd F32x4Ceil => visit_f32x4_ceil (unary v128f) - @simd F32x4Floor => visit_f32x4_floor (unary v128f) - @simd F32x4Trunc => visit_f32x4_trunc (unary v128f) - @simd F32x4Nearest => visit_f32x4_nearest (unary v128f) - @simd F32x4Abs => visit_f32x4_abs (unary v128f) - @simd F32x4Neg => visit_f32x4_neg (unary v128f) - @simd F32x4Sqrt => visit_f32x4_sqrt (unary v128f) - @simd F32x4Add => visit_f32x4_add (binary v128f) - @simd F32x4Sub => visit_f32x4_sub (binary v128f) - @simd F32x4Mul => visit_f32x4_mul (binary v128f) - @simd F32x4Div => visit_f32x4_div (binary v128f) - @simd F32x4Min => visit_f32x4_min (binary v128f) - @simd F32x4Max => visit_f32x4_max (binary v128f) - @simd F32x4PMin => visit_f32x4_pmin (binary v128f) - @simd F32x4PMax => visit_f32x4_pmax (binary v128f) - @simd F64x2Ceil => visit_f64x2_ceil (unary v128f) - @simd F64x2Floor => visit_f64x2_floor (unary v128f) - @simd F64x2Trunc => visit_f64x2_trunc (unary v128f) - @simd F64x2Nearest => visit_f64x2_nearest (unary v128f) - @simd F64x2Abs => visit_f64x2_abs (unary v128f) - @simd F64x2Neg => visit_f64x2_neg (unary v128f) - @simd F64x2Sqrt => visit_f64x2_sqrt (unary v128f) - @simd F64x2Add => visit_f64x2_add (binary v128f) - @simd F64x2Sub => visit_f64x2_sub (binary v128f) - @simd F64x2Mul => visit_f64x2_mul (binary v128f) - @simd F64x2Div => visit_f64x2_div (binary v128f) - @simd F64x2Min => visit_f64x2_min (binary v128f) - @simd F64x2Max => visit_f64x2_max (binary v128f) - @simd F64x2PMin => visit_f64x2_pmin (binary v128f) - @simd F64x2PMax => visit_f64x2_pmax (binary v128f) - @simd I32x4TruncSatF32x4S => visit_i32x4_trunc_sat_f32x4_s (unary v128f) - @simd I32x4TruncSatF32x4U => visit_i32x4_trunc_sat_f32x4_u (unary v128f) - @simd F32x4ConvertI32x4S => visit_f32x4_convert_i32x4_s (unary v128f) - @simd F32x4ConvertI32x4U => visit_f32x4_convert_i32x4_u (unary v128f) - @simd I32x4TruncSatF64x2SZero => visit_i32x4_trunc_sat_f64x2_s_zero (unary v128f) - @simd I32x4TruncSatF64x2UZero => visit_i32x4_trunc_sat_f64x2_u_zero (unary v128f) - @simd F64x2ConvertLowI32x4S => visit_f64x2_convert_low_i32x4_s (unary v128f) - @simd F64x2ConvertLowI32x4U => visit_f64x2_convert_low_i32x4_u (unary v128f) - @simd F32x4DemoteF64x2Zero => visit_f32x4_demote_f64x2_zero (unary v128f) - @simd F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 (unary v128f) - - // Relaxed SIMD operators - // https://github.com/WebAssembly/relaxed-simd - @relaxed_simd I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle (binary v128) - @relaxed_simd I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s (unary v128) - @relaxed_simd I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u (unary v128) - @relaxed_simd I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero (unary v128) - @relaxed_simd I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero (unary v128) - @relaxed_simd F32x4RelaxedMadd => visit_f32x4_relaxed_madd (ternary v128) - @relaxed_simd F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd (ternary v128) - @relaxed_simd F64x2RelaxedMadd => visit_f64x2_relaxed_madd (ternary v128) - @relaxed_simd F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd (ternary v128) - @relaxed_simd I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect (ternary v128) - @relaxed_simd I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect (ternary v128) - @relaxed_simd I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect (ternary v128) - @relaxed_simd I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect (ternary v128) - @relaxed_simd F32x4RelaxedMin => visit_f32x4_relaxed_min (binary v128) - @relaxed_simd F32x4RelaxedMax => visit_f32x4_relaxed_max (binary v128) - @relaxed_simd F64x2RelaxedMin => visit_f64x2_relaxed_min (binary v128) - @relaxed_simd F64x2RelaxedMax => visit_f64x2_relaxed_max (binary v128) - @relaxed_simd I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s (binary v128) - @relaxed_simd I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s (binary v128) - @relaxed_simd I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s (ternary v128) - - // Typed Function references - @function_references CallRef { type_index: u32 } => visit_call_ref (arity 1 type -> type) - @function_references ReturnCallRef { type_index: u32 } => visit_return_call_ref (arity 1 type -> 0) - @function_references RefAsNonNull => visit_ref_as_non_null (arity 1 -> 1) - @function_references BrOnNull { relative_depth: u32 } => visit_br_on_null (arity 1 br -> 1 br) - @function_references BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null (arity br -> br -1) - - // Stack switching - @stack_switching ContNew { cont_type_index: u32 } => visit_cont_new (arity 1 -> 1) - @stack_switching ContBind { argument_index: u32, result_index: u32 } => visit_cont_bind (arity type_diff 1 -> 1) - @stack_switching Suspend { tag_index: u32 } => visit_suspend (arity tag -> tag) - @stack_switching Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity 1 type -> type) - @stack_switching ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity 1 tag -> type) - @stack_switching Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity type -> ~switch) - - @wide_arithmetic I64Add128 => visit_i64_add128 (arity 4 -> 2) - @wide_arithmetic I64Sub128 => visit_i64_sub128 (arity 4 -> 2) - @wide_arithmetic I64MulWideS => visit_i64_mul_wide_s (arity 2 -> 2) - @wide_arithmetic I64MulWideU => visit_i64_mul_wide_u (arity 2 -> 2) - } - }; -} +/// Used to implement the [`VisitSimdOperator`] trait. +/// +/// The list of specializable Wasm proposals is as follows: +/// +/// - `@simd`: [Wasm `simd` proposal] +/// - `@relaxed_simd`: [Wasm `relaxed-simd` proposal] +/// +/// For more information about the structure and use of this macro please +/// refer to the documentation of the [`for_each_operator`] macro. +/// +/// [Wasm `simd` proposal]: +/// https://github.com/webassembly/simd +/// +/// [Wasm `relaxed-simd` proposal]: +/// https://github.com/WebAssembly/relaxed-simd +/// +/// [`VisitSimdOperator`]: crate::VisitSimdOperator +#[cfg(feature = "simd")] +#[doc(inline)] +pub use _for_each_visit_simd_operator_impl as for_each_visit_simd_operator; macro_rules! format_err { ($offset:expr, $($arg:tt)*) => { diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 2cdf21124a..80e71d3e5c 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -220,6 +220,7 @@ macro_rules! define_operator { /// [here]: https://webassembly.github.io/spec/core/binary/instructions.html #[derive(Debug, Clone, Eq, PartialEq)] #[allow(missing_docs)] + #[non_exhaustive] pub enum Operator<'a> { $( $op $({ $($payload)* })?, @@ -227,7 +228,7 @@ macro_rules! define_operator { } } } -for_each_operator!(define_operator); +crate::for_each_operator!(define_operator); /// A reader for a core WebAssembly function's operators. #[derive(Clone)] @@ -418,19 +419,73 @@ pub trait VisitOperator<'a> { /// implement [`VisitOperator`] on their own. fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { macro_rules! visit_operator { - ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {{ match op { - $( - Operator::$op $({ $($arg),* })? => self.$visit($($($arg.clone()),*)?), - )* + $( Operator::$op $({ $($arg),* })? => self.$visit($($($arg.clone()),*)?), )* + #[cfg(feature = "simd")] + other => visit_simd_operator(self, other), } - } - + }}; } - for_each_operator!(visit_operator) + crate::for_each_visit_operator!(visit_operator) } - for_each_operator!(define_visit_operator); + /// Returns a mutable reference to a [`VisitSimdOperator`] visitor. + /// + /// - If an implementer does _not_ want to support Wasm `simd` proposal + /// nothing has to be done since the default implementation already suffices. + /// - If an implementer _does_ want to support Wasm `simd` proposal this + /// method usually is implemented as `Some(self)` where the implementing + /// type (`Self`) typically also implements `VisitSimdOperator`. + /// + /// # Example + /// + /// ```compile_fail + /// impl VisitOperator for MyVisitor { + /// fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + /// Some(self) + /// } + /// + /// // implement remaining visitation methods here ... + /// } + /// + /// impl VisitSimdOperator for MyVisitor { + /// // implement SIMD visitation methods here ... + /// } + /// ``` + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + None + } + + crate::for_each_visit_operator!(define_visit_operator); +} + +/// Special handler for visiting `simd` and `relaxed-simd` [`Operator`] variants. +#[cfg(feature = "simd")] +fn visit_simd_operator<'a, V>(visitor: &mut V, op: &Operator<'a>) -> V::Output +where + V: VisitOperator<'a> + ?Sized, +{ + let Some(simd_visitor) = visitor.simd_visitor() else { + panic!("missing SIMD visitor to visit operator: {op:?}") + }; + macro_rules! visit_simd_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {{ + match op { + $( Operator::$op $({ $($arg),* })? => simd_visitor.$visit($($($arg.clone()),*)?), )* + unexpected => unreachable!("unexpected non-SIMD operator: {unexpected:?}"), + } + }}; + } + crate::for_each_visit_simd_operator!(visit_simd_operator) +} + +/// Trait implemented by types that can visit all Wasm `simd` and `relaxed-simd` [`Operator`]s. +#[cfg(feature = "simd")] +#[allow(missing_docs)] +pub trait VisitSimdOperator<'a>: VisitOperator<'a> { + crate::for_each_visit_simd_operator!(define_visit_operator); } macro_rules! define_visit_operator_delegate { @@ -448,7 +503,16 @@ impl<'a, 'b, V: VisitOperator<'a> + ?Sized> VisitOperator<'a> for &'b mut V { fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { V::visit_operator(*self, op) } - for_each_operator!(define_visit_operator_delegate); + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = V::Output>> { + V::simd_visitor(*self) + } + crate::for_each_visit_operator!(define_visit_operator_delegate); +} + +#[cfg(feature = "simd")] +impl<'a, 'b, V: VisitSimdOperator<'a> + ?Sized> VisitSimdOperator<'a> for &'b mut V { + crate::for_each_visit_simd_operator!(define_visit_operator_delegate); } impl<'a, V: VisitOperator<'a> + ?Sized> VisitOperator<'a> for Box { @@ -456,7 +520,16 @@ impl<'a, V: VisitOperator<'a> + ?Sized> VisitOperator<'a> for Box { fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { V::visit_operator(&mut *self, op) } - for_each_operator!(define_visit_operator_delegate); + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = V::Output>> { + V::simd_visitor(&mut *self) + } + crate::for_each_visit_operator!(define_visit_operator_delegate); +} + +#[cfg(feature = "simd")] +impl<'a, V: VisitSimdOperator<'a> + ?Sized> VisitSimdOperator<'a> for Box { + crate::for_each_visit_simd_operator!(define_visit_operator_delegate); } /// A `try_table` entries representation. diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 4f2deb0629..f0d1d49b28 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -10,6 +10,8 @@ use super::{ operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations}, types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList}, }; +#[cfg(feature = "simd")] +use crate::VisitSimdOperator; use crate::{ limits::*, BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, @@ -431,7 +433,7 @@ impl ModuleState { $self.validator().visit_f64_const($val) }}; (@visit $self:ident visit_v128_const $val:ident) => {{ - $self.validator().visit_v128_const($val) + $self.validator().simd_visitor().unwrap().visit_v128_const($val) }}; (@visit $self:ident visit_ref_null $val:ident) => {{ $self.validator().visit_ref_null($val) @@ -522,7 +524,19 @@ impl ModuleState { impl<'a> VisitOperator<'a> for VisitConstOperator<'a> { type Output = Result<()>; - for_each_operator!(define_visit_operator); + #[cfg(feature = "simd")] + fn simd_visitor( + &mut self, + ) -> Option<&mut dyn crate::VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + crate::for_each_visit_operator!(define_visit_operator); + } + + #[cfg(feature = "simd")] + impl<'a> VisitSimdOperator<'a> for VisitConstOperator<'a> { + crate::for_each_visit_simd_operator!(define_visit_operator); } } } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 758447f3de..9a3a8c391f 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -22,15 +22,20 @@ // confusing it's recommended to read over that section to see how it maps to // the various methods here. +#[cfg(feature = "simd")] +use crate::VisitSimdOperator; use crate::{ limits::MAX_WASM_FUNCTION_LOCALS, AbstractHeapType, BinaryReaderError, BlockType, BrTable, Catch, ContType, FieldType, FrameKind, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, MemArg, ModuleArity, RefType, Result, ResumeTable, StorageType, StructType, SubType, TableType, - TryTable, UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, V128, + TryTable, UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, }; use crate::{prelude::*, CompositeInnerType, Ordering}; use core::ops::{Deref, DerefMut}; +#[cfg(feature = "simd")] +mod simd; + pub(crate) struct OperatorValidator { pub(super) locals: Locals, local_inits: LocalInits, @@ -1022,13 +1027,6 @@ where self.check_memory_index(memarg.memory) } - fn check_simd_lane_index(&self, index: u8, max: u8) -> Result<()> { - if index >= max { - bail!(self.offset, "SIMD index out of bounds"); - } - Ok(()) - } - /// Validates a block type, primarily with various in-flight proposals. fn check_block_type(&self, ty: &mut BlockType) -> Result<()> { match ty { @@ -1286,72 +1284,6 @@ where Ok(()) } - /// Checks a [`V128`] splat operator. - fn check_v128_splat(&mut self, src_ty: ValType) -> Result<()> { - self.pop_operand(Some(src_ty))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - - /// Checks a [`V128`] binary operator. - fn check_v128_binary_op(&mut self) -> Result<()> { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - - /// Checks a [`V128`] binary float operator. - fn check_v128_fbinary_op(&mut self) -> Result<()> { - self.check_floats_enabled()?; - self.check_v128_binary_op() - } - - /// Checks a [`V128`] unary operator. - fn check_v128_unary_op(&mut self) -> Result<()> { - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - - /// Checks a [`V128`] unary float operator. - fn check_v128_funary_op(&mut self) -> Result<()> { - self.check_floats_enabled()?; - self.check_v128_unary_op() - } - - /// Checks a [`V128`] relaxed ternary operator. - fn check_v128_ternary_op(&mut self) -> Result<()> { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - - /// Checks a [`V128`] test operator. - fn check_v128_bitmask_op(&mut self) -> Result<()> { - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::I32)?; - Ok(()) - } - - /// Checks a [`V128`] shift operator. - fn check_v128_shift_op(&mut self) -> Result<()> { - self.pop_operand(Some(ValType::I32))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - - /// Checks a [`V128`] common load operator. - fn check_v128_load_op(&mut self, memarg: MemArg) -> Result<()> { - let idx = self.check_memarg(memarg)?; - self.pop_operand(Some(idx))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - /// Common helper for `ref.test` and `ref.cast` downcasting/checking /// instructions. Returns the given `heap_type` as a `ValType`. fn check_downcast(&mut self, nullable: bool, mut heap_type: HeapType) -> Result { @@ -1823,7 +1755,20 @@ where { type Output = Result<()>; - for_each_operator!(validate_proposal); + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + crate::for_each_visit_operator!(validate_proposal); +} + +#[cfg(feature = "simd")] +impl<'a, T> VisitSimdOperator<'a> for WasmProposalValidator<'_, '_, T> +where + T: WasmModuleResources, +{ + crate::for_each_visit_simd_operator!(validate_proposal); } #[track_caller] @@ -1847,6 +1792,11 @@ where { type Output = Result<()>; + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + fn visit_nop(&mut self) -> Self::Output { Ok(()) } @@ -3129,890 +3079,6 @@ where } self.push_operand(ValType::I32) } - fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg)?; - self.pop_operand(Some(ty))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ty))?; - Ok(()) - } - fn visit_v128_const(&mut self, _value: V128) -> Self::Output { - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i8x16_splat(&mut self) -> Self::Output { - self.check_v128_splat(ValType::I32) - } - fn visit_i16x8_splat(&mut self) -> Self::Output { - self.check_v128_splat(ValType::I32) - } - fn visit_i32x4_splat(&mut self) -> Self::Output { - self.check_v128_splat(ValType::I32) - } - fn visit_i64x2_splat(&mut self) -> Self::Output { - self.check_v128_splat(ValType::I64) - } - fn visit_f32x4_splat(&mut self) -> Self::Output { - self.check_floats_enabled()?; - self.check_v128_splat(ValType::F32) - } - fn visit_f64x2_splat(&mut self) -> Self::Output { - self.check_floats_enabled()?; - self.check_v128_splat(ValType::F64) - } - fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::I32)?; - Ok(()) - } - fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output { - self.visit_i8x16_extract_lane_s(lane) - } - fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::I32)?; - Ok(()) - } - fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output { - self.visit_i16x8_extract_lane_s(lane) - } - fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::I32)?; - Ok(()) - } - fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(ValType::I32))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(ValType::I32))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::I32))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::I64)?; - Ok(()) - } - fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::I64))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output { - self.check_floats_enabled()?; - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::F32)?; - Ok(()) - } - fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_floats_enabled()?; - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::F32))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output { - self.check_floats_enabled()?; - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::F64)?; - Ok(()) - } - fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output { - self.check_floats_enabled()?; - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::F64))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_f32x4_eq(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_ne(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_lt(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_gt(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_le(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_ge(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_eq(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_ne(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_lt(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_gt(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_le(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_ge(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_add(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_sub(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_mul(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_div(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_min(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_max(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_pmin(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f32x4_pmax(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_add(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_sub(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_mul(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_div(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_min(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_max(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_pmin(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_f64x2_pmax(&mut self) -> Self::Output { - self.check_v128_fbinary_op() - } - fn visit_i8x16_eq(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_ne(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_lt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_lt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_gt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_gt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_le_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_le_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_ge_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_ge_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_eq(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_ne(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_lt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_lt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_gt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_gt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_le_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_le_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_ge_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_ge_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_eq(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_ne(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_lt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_lt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_gt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_gt_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_le_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_le_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_ge_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_ge_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_eq(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_ne(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_lt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_gt_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_le_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_ge_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_v128_and(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_v128_andnot(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_v128_or(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_v128_xor(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_add(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_add_sat_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_add_sat_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_sub(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_min_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_min_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_max_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_max_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_add(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_add_sat_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_add_sat_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_sub(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_mul(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_min_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_min_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_max_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_max_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_add(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_sub(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_mul(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_min_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_min_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_max_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_max_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_add(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_sub(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_mul(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_avgr_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_avgr_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_f32x4_ceil(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_floor(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_trunc(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_nearest(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_ceil(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_floor(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_trunc(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_nearest(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_abs(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_neg(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_sqrt(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_abs(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_neg(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_sqrt(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output { - self.check_v128_funary_op() - } - fn visit_v128_not(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i8x16_abs(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i8x16_neg(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i8x16_popcnt(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_abs(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_neg(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_abs(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_neg(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_abs(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_neg(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_v128_bitselect(&mut self) -> Self::Output { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i32x4_relaxed_trunc_f32x4_s(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_relaxed_trunc_f32x4_u(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> Self::Output { - self.check_v128_unary_op() - } - fn visit_f32x4_relaxed_madd(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_f32x4_relaxed_nmadd(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_f64x2_relaxed_madd(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_f64x2_relaxed_nmadd(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_f32x4_relaxed_min(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_f32x4_relaxed_max(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_f64x2_relaxed_min(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_f64x2_relaxed_max(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> Self::Output { - self.check_v128_binary_op() - } - fn visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output { - self.check_v128_ternary_op() - } - fn visit_v128_any_true(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i8x16_all_true(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i8x16_bitmask(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i16x8_all_true(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i16x8_bitmask(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i32x4_all_true(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i32x4_bitmask(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i64x2_all_true(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i64x2_bitmask(&mut self) -> Self::Output { - self.check_v128_bitmask_op() - } - fn visit_i8x16_shl(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i8x16_shr_s(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i8x16_shr_u(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i16x8_shl(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i16x8_shr_s(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i16x8_shr_u(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i32x4_shl(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i32x4_shr_s(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i32x4_shr_u(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i64x2_shl(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i64x2_shr_s(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i64x2_shr_u(&mut self) -> Self::Output { - self.check_v128_shift_op() - } - fn visit_i8x16_swizzle(&mut self) -> Self::Output { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(ValType::V128))?; - for i in lanes { - self.check_simd_lane_index(i, 32)?; - } - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg)?; - self.pop_operand(Some(ty))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg)?; - self.pop_operand(Some(ty))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg)?; - self.pop_operand(Some(ty))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output { - self.visit_v128_load32_splat(memarg) - } - fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(memarg) - } - fn visit_v128_load8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_load64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - self.push_operand(ValType::V128)?; - Ok(()) - } - fn visit_v128_store8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - Ok(()) - } - fn visit_v128_store16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - Ok(()) - } - fn visit_v128_store32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - Ok(()) - } - fn visit_v128_store64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { - let idx = self.check_memarg(memarg)?; - self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(ValType::V128))?; - self.pop_operand(Some(idx))?; - Ok(()) - } fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output { let ty = self.check_memory_index(mem)?; self.check_data_segment(segment)?; diff --git a/crates/wasmparser/src/validator/operators/simd.rs b/crates/wasmparser/src/validator/operators/simd.rs new file mode 100644 index 0000000000..b52015a259 --- /dev/null +++ b/crates/wasmparser/src/validator/operators/simd.rs @@ -0,0 +1,971 @@ +use super::OperatorValidatorTemp; +use crate::{MemArg, Result, ValType, WasmModuleResources}; +use crate::{VisitSimdOperator, V128}; + +impl<'resources, R> OperatorValidatorTemp<'_, 'resources, R> +where + R: WasmModuleResources, +{ + fn check_simd_lane_index(&self, index: u8, max: u8) -> Result<()> { + if index >= max { + bail!(self.offset, "SIMD index out of bounds"); + } + Ok(()) + } + + /// Checks a [`V128`] splat operator. + fn check_v128_splat(&mut self, src_ty: ValType) -> Result<()> { + self.pop_operand(Some(src_ty))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + + /// Checks a [`V128`] binary operator. + fn check_v128_binary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + + /// Checks a [`V128`] binary float operator. + fn check_v128_fbinary_op(&mut self) -> Result<()> { + self.check_floats_enabled()?; + self.check_v128_binary_op() + } + + /// Checks a [`V128`] unary operator. + fn check_v128_unary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + + /// Checks a [`V128`] unary float operator. + fn check_v128_funary_op(&mut self) -> Result<()> { + self.check_floats_enabled()?; + self.check_v128_unary_op() + } + + /// Checks a [`V128`] relaxed ternary operator. + fn check_v128_ternary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + + /// Checks a [`V128`] test operator. + fn check_v128_bitmask_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; + Ok(()) + } + + /// Checks a [`V128`] shift operator. + fn check_v128_shift_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + + /// Checks a [`V128`] common load operator. + fn check_v128_load_op(&mut self, memarg: MemArg) -> Result<()> { + let idx = self.check_memarg(memarg)?; + self.pop_operand(Some(idx))?; + self.push_operand(ValType::V128)?; + Ok(()) + } +} + +impl<'a, T> VisitSimdOperator<'a> for OperatorValidatorTemp<'_, '_, T> +where + T: WasmModuleResources, +{ + fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ty))?; + Ok(()) + } + fn visit_v128_const(&mut self, _value: V128) -> Self::Output { + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i8x16_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) + } + fn visit_i16x8_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) + } + fn visit_i32x4_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) + } + fn visit_i64x2_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I64) + } + fn visit_f32x4_splat(&mut self) -> Self::Output { + self.check_floats_enabled()?; + self.check_v128_splat(ValType::F32) + } + fn visit_f64x2_splat(&mut self) -> Self::Output { + self.check_floats_enabled()?; + self.check_v128_splat(ValType::F64) + } + fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; + Ok(()) + } + fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output { + self.visit_i8x16_extract_lane_s(lane) + } + fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; + Ok(()) + } + fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output { + self.visit_i16x8_extract_lane_s(lane) + } + fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; + Ok(()) + } + fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I64)?; + Ok(()) + } + fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::F32)?; + Ok(()) + } + fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::F64)?; + Ok(()) + } + fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_f32x4_eq(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_ne(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_lt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_gt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_le(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_ge(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_eq(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_ne(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_lt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_gt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_le(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_ge(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_add(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_sub(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_mul(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_div(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_min(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_max(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_pmin(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f32x4_pmax(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_add(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_sub(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_mul(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_div(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_min(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_max(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_pmin(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_f64x2_pmax(&mut self) -> Self::Output { + self.check_v128_fbinary_op() + } + fn visit_i8x16_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_v128_and(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_v128_andnot(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_v128_or(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_v128_xor(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_add(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_add_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_add_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_add(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_add_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_add_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_add(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_add(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_avgr_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_avgr_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_f32x4_ceil(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_floor(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_trunc(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_nearest(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_ceil(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_floor(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_trunc(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_nearest(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_abs(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_neg(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_sqrt(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_abs(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_neg(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_sqrt(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() + } + fn visit_v128_not(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i8x16_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i8x16_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i8x16_popcnt(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_v128_bitselect(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i32x4_relaxed_trunc_f32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_relaxed_trunc_f32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> Self::Output { + self.check_v128_unary_op() + } + fn visit_f32x4_relaxed_madd(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_f32x4_relaxed_nmadd(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_f64x2_relaxed_madd(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_f64x2_relaxed_nmadd(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_f32x4_relaxed_min(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_f32x4_relaxed_max(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_f64x2_relaxed_min(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_f64x2_relaxed_max(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() + } + fn visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output { + self.check_v128_ternary_op() + } + fn visit_v128_any_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i8x16_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i8x16_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i16x8_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i16x8_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i32x4_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i32x4_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i64x2_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i64x2_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() + } + fn visit_i8x16_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i8x16_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i8x16_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i16x8_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i16x8_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i16x8_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i32x4_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i32x4_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i32x4_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i64x2_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i64x2_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i64x2_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i8x16_swizzle(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + for i in lanes { + self.check_simd_lane_index(i, 32)?; + } + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output { + self.visit_v128_load32_splat(memarg) + } + fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) + } + fn visit_v128_load8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_load64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + self.push_operand(ValType::V128)?; + Ok(()) + } + fn visit_v128_store8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + Ok(()) + } + fn visit_v128_store16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + Ok(()) + } + fn visit_v128_store32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + Ok(()) + } + fn visit_v128_store64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; + Ok(()) + } +} diff --git a/crates/wasmprinter/Cargo.toml b/crates/wasmprinter/Cargo.toml index d873494223..de8f3807a5 100644 --- a/crates/wasmprinter/Cargo.toml +++ b/crates/wasmprinter/Cargo.toml @@ -18,7 +18,7 @@ workspace = true [dependencies] anyhow = { workspace = true } -wasmparser = { workspace = true, features = ['std'] } +wasmparser = { workspace = true, features = ['std', 'simd'] } termcolor = { workspace = true } [dev-dependencies] diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs index 6456ecc3d9..5b6f728dfc 100644 --- a/crates/wasmprinter/src/operator.rs +++ b/crates/wasmprinter/src/operator.rs @@ -1,6 +1,7 @@ use super::{Config, Print, PrintTermcolor, Printer, State}; use anyhow::{anyhow, bail, Result}; use termcolor::{Ansi, NoColor}; +use wasmparser::VisitSimdOperator; use wasmparser::{ BinaryReader, BlockType, BrTable, Catch, CompositeInnerType, ContType, FrameKind, FuncType, Handle, MemArg, ModuleArity, Operator, Ordering, RefType, ResumeTable, SubType, TryTable, @@ -1389,7 +1390,15 @@ macro_rules! define_visit { impl<'a> VisitOperator<'a> for PrintOperator<'_, '_, '_, '_> { type Output = Result<()>; - wasmparser::for_each_operator!(define_visit); + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + wasmparser::for_each_visit_operator!(define_visit); +} + +impl<'a> VisitSimdOperator<'a> for PrintOperator<'_, '_, '_, '_> { + wasmparser::for_each_visit_simd_operator!(define_visit); } pub trait OpPrinter { diff --git a/crates/wit-component/Cargo.toml b/crates/wit-component/Cargo.toml index 87bb285454..0155909957 100644 --- a/crates/wit-component/Cargo.toml +++ b/crates/wit-component/Cargo.toml @@ -20,7 +20,7 @@ workspace = true all-features = true [dependencies] -wasmparser = { workspace = true, features = ['component-model'] } +wasmparser = { workspace = true, features = ['component-model', 'simd'] } wasm-encoder = { workspace = true, features = ["wasmparser"] } wasm-metadata = { workspace = true } wit-parser = { workspace = true, features = ['decoding', 'serde'] } diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs index ff4b5648c4..55d3be513b 100644 --- a/crates/wit-component/src/gc.rs +++ b/crates/wit-component/src/gc.rs @@ -991,7 +991,15 @@ macro_rules! define_visit { impl<'a> VisitOperator<'a> for Module<'a> { type Output = (); - wasmparser::for_each_operator!(define_visit); + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + wasmparser::for_each_visit_operator!(define_visit); +} + +impl<'a> VisitSimdOperator<'a> for Module<'a> { + wasmparser::for_each_visit_simd_operator!(define_visit); } /// Helper function to filter `iter` based on the `live` set, yielding an diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index 8a8ef69219..5379956851 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -831,5 +831,13 @@ macro_rules! define_visit_operator { impl<'a> VisitOperator<'a> for Dump<'_> { type Output = (); - wasmparser::for_each_operator!(define_visit_operator); + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + wasmparser::for_each_visit_operator!(define_visit_operator); +} + +impl<'a> VisitSimdOperator<'a> for Dump<'_> { + wasmparser::for_each_visit_simd_operator!(define_visit_operator); }