Path: blob/main/crates/fuzzing/src/generators/single_inst_module.rs
1693 views
//! Generate Wasm modules that contain a single instruction.12use super::ModuleConfig;3use arbitrary::Unstructured;4use wasm_encoder::{5CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, Module,6TypeSection, ValType,7};89/// The name of the function generated by this module.10const FUNCTION_NAME: &'static str = "test";1112/// Configure a single instruction module.13///14/// By explicitly defining the parameter and result types (versus generating the15/// module directly), we can more easily generate values of the right type.16#[derive(Clone)]17pub struct SingleInstModule<'a> {18instruction: Instruction<'a>,19parameters: &'a [ValType],20results: &'a [ValType],21feature: fn(&ModuleConfig) -> bool,22canonicalize_nan: Option<NanType>,23}2425/// Valid types for NaN canonicalization.26///27/// When fuzzing floating point values, a NaN result can have non-deterministic28/// bits in the payload. In order to compare these results, [`SingleInstModule`]29/// can convert any NaN values (or NaN lanes) to a canonical NaN value for any30/// of these types.31#[derive(Clone)]32enum NanType {33#[expect(dead_code, reason = "expected to be used in the future")]34F32,35#[expect(dead_code, reason = "expected to be used in the future")]36F64,37F32x4,38F64x2,39}4041impl<'a> SingleInstModule<'a> {42/// Choose a single-instruction module that matches `config`.43pub fn new(u: &mut Unstructured<'a>, config: &ModuleConfig) -> arbitrary::Result<&'a Self> {44// Only select instructions that match the `ModuleConfig`.45let instructions = &INSTRUCTIONS46.iter()47.filter(|i| (i.feature)(config))48.collect::<Vec<_>>();49u.choose(&instructions[..]).copied()50}5152/// Encode a binary Wasm module with a single exported function, `test`,53/// that executes the single instruction.54pub fn to_bytes(&self) -> Vec<u8> {55let mut module = Module::new();5657// Encode the type section.58let mut types = TypeSection::new();59types.ty().function(60self.parameters.iter().cloned(),61self.results.iter().cloned(),62);63module.section(&types);6465// Encode the function section.66let mut functions = FunctionSection::new();67let type_index = 0;68functions.function(type_index);69module.section(&functions);7071// Encode the export section.72let mut exports = ExportSection::new();73exports.export(FUNCTION_NAME, ExportKind::Func, 0);74module.section(&exports);7576// Encode the code section.77let mut codes = CodeSection::new();7879// Set up the single-instruction function. Note that if we have chosen80// to canonicalize NaNs, this function will contain more than one81// instruction and the function will need a scratch local.82let mut f = if let Some(ty) = &self.canonicalize_nan {83Function::new(match ty {84NanType::F32 => vec![(1, ValType::F32)],85NanType::F64 => vec![(1, ValType::F64)],86NanType::F32x4 | NanType::F64x2 => vec![(1, ValType::V128)],87})88} else {89Function::new([])90};9192// Retrieve the input values and execute the chosen instruction.93for (index, _) in self.parameters.iter().enumerate() {94f.instruction(&Instruction::LocalGet(index as u32));95}96f.instruction(&self.instruction);9798// If we have configured to canonicalize NaNs, we add a sequence that99// masks off the NaN payload bits to make them 0s (i.e., a canonical100// NaN). This sequence is adapted from wasm-smiths version; see101// https://github.com/bytecodealliance/wasm-tools/blob/6c127a6/crates/wasm-smith/src/core/code_builder.rs#L927.102if let Some(ty) = &self.canonicalize_nan {103// Save the previous instruction's result into the scratch local.104// This also leaves a value on the stack as for the `select`105// instruction.106let local = self.parameters.len() as u32;107f.instruction(&Instruction::LocalTee(local));108109// The other input to the `select` below--a canonical NaN. Note how110// the payload bits of the NaN are cleared.111const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000;112const CANON_64BIT_NAN: u64 =1130b0111111111111000000000000000000000000000000000000000000000000000;114let mask = match ty {115NanType::F32 => Instruction::F32Const(f32::from_bits(CANON_32BIT_NAN).into()),116NanType::F64 => Instruction::F64Const(f64::from_bits(CANON_64BIT_NAN).into()),117NanType::F32x4 => {118let nan = CANON_32BIT_NAN as i128;119Instruction::V128Const(nan | (nan << 32) | (nan << 64) | (nan << 96))120}121NanType::F64x2 => {122let nan = CANON_64BIT_NAN as i128;123Instruction::V128Const(nan | (nan << 64))124}125};126f.instruction(&mask);127128// The `select` condition. NaNs never equal each other, so here the129// result value is compared against itself.130f.instruction(&Instruction::LocalGet(local));131f.instruction(&Instruction::LocalGet(local));132f.instruction(match ty {133NanType::F32 => &Instruction::F32Eq,134NanType::F64 => &Instruction::F64Eq,135NanType::F32x4 => &Instruction::F32x4Eq,136NanType::F64x2 => &Instruction::F64x2Eq,137});138139// Select the result. If the condition is nonzero (i.e., the float140// is equal to itself) it picks the original value; otherwise, if141// zero (i.e., the float is a NaN) it picks the canonical NaN value.142f.instruction(match ty {143NanType::F32 | NanType::F64 => &Instruction::Select,144NanType::F32x4 | NanType::F64x2 => &Instruction::V128Bitselect,145});146}147148// Wrap up the function and section.149f.instruction(&Instruction::End);150codes.function(&f);151module.section(&codes);152153// Extract the encoded Wasm bytes for this module.154module.finish()155}156}157158// MACROS159//160// These macros make it a bit easier to define the instructions available for161// generation. The idea is that, with these macros, we can define the list of162// instructions compactly and allow for easier changes to the Rust code (e.g.,163// `SingleInstModule`).164165macro_rules! valtypes {166(@list ($($ty:tt),*)) => {&[$(valtypes!(@one $ty)),*]};167(@list $ty:tt) => {&[valtypes!(@one $ty)]};168(@one i32) => {169ValType::I32170};171(@one i64) => {172ValType::I64173};174(@one f32) => {175ValType::F32176};177(@one f64) => {178ValType::F64179};180(@one v128) => {181ValType::V128182};183}184185macro_rules! inst {186($inst:ident, $arguments:tt -> $results:tt) => {187inst! { $inst, $arguments -> $results, |_| true }188};189($inst:ident, $arguments:tt -> $results:tt, $feature:expr) => {190inst! { $inst, $arguments -> $results, $feature, None }191};192($inst:ident, $arguments:tt -> $results:tt, $feature:expr, $nan:expr) => {193SingleInstModule {194instruction: Instruction::$inst,195parameters: valtypes!(@list $arguments),196results: valtypes!(@list $results),197feature: $feature,198canonicalize_nan: $nan,199}200};201}202203// INSTRUCTIONS204//205// This list of WebAssembly instructions attempts to roughly follow the206// structure of the W3C specification:207// https://webassembly.github.io/spec/core/appendix/index-instructions.html#index-instr.208// Certain kinds of instructions (e.g., memory access) are skipped for now.209static INSTRUCTIONS: &[SingleInstModule] = &[210// Integer arithmetic.211// I32Const212// I64Const213// F32Const214// F64Const215inst!(I32Clz, (i32) -> i32),216inst!(I64Clz, (i64) -> i64),217inst!(I32Ctz, (i32) -> i32),218inst!(I64Ctz, (i64) -> i64),219inst!(I32Popcnt, (i32) -> i32),220inst!(I64Popcnt, (i64) -> i64),221inst!(I32Add, (i32, i32) -> i32),222inst!(I64Add, (i64, i64) -> i64),223inst!(I32Sub, (i32, i32) -> i32),224inst!(I64Sub, (i64, i64) -> i64),225inst!(I32Mul, (i32, i32) -> i32),226inst!(I64Mul, (i64, i64) -> i64),227inst!(I32DivS, (i32, i32) -> i32),228inst!(I64DivS, (i64, i64) -> i64),229inst!(I32DivU, (i32, i32) -> i32),230inst!(I64DivU, (i64, i64) -> i64),231inst!(I32RemS, (i32, i32) -> i32),232inst!(I64RemS, (i64, i64) -> i64),233inst!(I32RemU, (i32, i32) -> i32),234inst!(I64RemU, (i64, i64) -> i64),235// Integer bitwise.236inst!(I32And, (i32, i32) -> i32),237inst!(I64And, (i64, i64) -> i64),238inst!(I32Or, (i32, i32) -> i32),239inst!(I64Or, (i64, i64) -> i64),240inst!(I32Xor, (i32, i32) -> i32),241inst!(I64Xor, (i64, i64) -> i64),242inst!(I32Shl, (i32, i32) -> i32),243inst!(I64Shl, (i64, i64) -> i64),244inst!(I32ShrS, (i32, i32) -> i32),245inst!(I64ShrS, (i64, i64) -> i64),246inst!(I32ShrU, (i32, i32) -> i32),247inst!(I64ShrU, (i64, i64) -> i64),248inst!(I32Rotl, (i32, i32) -> i32),249inst!(I64Rotl, (i64, i64) -> i64),250inst!(I32Rotr, (i32, i32) -> i32),251inst!(I64Rotr, (i64, i64) -> i64),252// Integer comparison.253inst!(I32Eqz, (i32) -> i32),254inst!(I64Eqz, (i64) -> i32),255inst!(I32Eq, (i32, i32) -> i32),256inst!(I64Eq, (i64, i64) -> i32),257inst!(I32Ne, (i32, i32) -> i32),258inst!(I64Ne, (i64, i64) -> i32),259inst!(I32LtS, (i32, i32) -> i32),260inst!(I64LtS, (i64, i64) -> i32),261inst!(I32LtU, (i32, i32) -> i32),262inst!(I64LtU, (i64, i64) -> i32),263inst!(I32GtS, (i32, i32) -> i32),264inst!(I64GtS, (i64, i64) -> i32),265inst!(I32GtU, (i32, i32) -> i32),266inst!(I64GtU, (i64, i64) -> i32),267inst!(I32LeS, (i32, i32) -> i32),268inst!(I64LeS, (i64, i64) -> i32),269inst!(I32LeU, (i32, i32) -> i32),270inst!(I64LeU, (i64, i64) -> i32),271inst!(I32GeS, (i32, i32) -> i32),272inst!(I64GeS, (i64, i64) -> i32),273inst!(I32GeU, (i32, i32) -> i32),274inst!(I64GeU, (i64, i64) -> i32),275// Floating-point arithmetic.276inst!(F32Abs, (f32) -> f32),277inst!(F64Abs, (f64) -> f64),278inst!(F32Sqrt, (f32) -> f32),279inst!(F64Sqrt, (f64) -> f64),280inst!(F32Ceil, (f32) -> f32),281inst!(F64Ceil, (f64) -> f64),282inst!(F32Floor, (f32) -> f32),283inst!(F64Floor, (f64) -> f64),284inst!(F32Trunc, (f32) -> f32),285inst!(F64Trunc, (f64) -> f64),286inst!(F32Nearest, (f32) -> f32),287inst!(F64Nearest, (f64) -> f64),288inst!(F32Neg, (f32) -> f32),289inst!(F64Neg, (f64) -> f64),290inst!(F32Add, (f32, f32) -> f32),291inst!(F64Add, (f64, f64) -> f64),292inst!(F32Sub, (f32, f32) -> f32),293inst!(F64Sub, (f64, f64) -> f64),294inst!(F32Mul, (f32, f32) -> f32),295inst!(F64Mul, (f64, f64) -> f64),296inst!(F32Div, (f32, f32) -> f32),297inst!(F64Div, (f64, f64) -> f64),298inst!(F32Min, (f32, f32) -> f32),299inst!(F64Min, (f64, f64) -> f64),300inst!(F32Max, (f32, f32) -> f32),301inst!(F64Max, (f64, f64) -> f64),302inst!(F32Copysign, (f32, f32) -> f32),303inst!(F64Copysign, (f64, f64) -> f64),304// Floating-point comparison.305inst!(F32Eq, (f32, f32) -> i32),306inst!(F64Eq, (f64, f64) -> i32),307inst!(F32Ne, (f32, f32) -> i32),308inst!(F64Ne, (f64, f64) -> i32),309inst!(F32Lt, (f32, f32) -> i32),310inst!(F64Lt, (f64, f64) -> i32),311inst!(F32Gt, (f32, f32) -> i32),312inst!(F64Gt, (f64, f64) -> i32),313inst!(F32Le, (f32, f32) -> i32),314inst!(F64Le, (f64, f64) -> i32),315inst!(F32Ge, (f32, f32) -> i32),316inst!(F64Ge, (f64, f64) -> i32),317// Integer conversions ("to integer").318inst!(I32Extend8S, (i32) -> i32, |c| c.config.sign_extension_ops_enabled),319inst!(I32Extend16S, (i32) -> i32, |c| c.config.sign_extension_ops_enabled),320inst!(I64Extend8S, (i64) -> i64, |c| c.config.sign_extension_ops_enabled),321inst!(I64Extend16S, (i64) -> i64, |c| c.config.sign_extension_ops_enabled),322inst!(I64Extend32S, (i64) -> i64, |c| c.config.sign_extension_ops_enabled),323inst!(I32WrapI64, (i64) -> i32),324inst!(I64ExtendI32S, (i32) -> i64),325inst!(I64ExtendI32U, (i32) -> i64),326inst!(I32TruncF32S, (f32) -> i32),327inst!(I32TruncF32U, (f32) -> i32),328inst!(I32TruncF64S, (f64) -> i32),329inst!(I32TruncF64U, (f64) -> i32),330inst!(I64TruncF32S, (f32) -> i64),331inst!(I64TruncF32U, (f32) -> i64),332inst!(I64TruncF64S, (f64) -> i64),333inst!(I64TruncF64U, (f64) -> i64),334inst!(I32TruncSatF32S, (f32) -> i32, |c| c.config.saturating_float_to_int_enabled),335inst!(I32TruncSatF32U, (f32) -> i32, |c| c.config.saturating_float_to_int_enabled),336inst!(I32TruncSatF64S, (f64) -> i32, |c| c.config.saturating_float_to_int_enabled),337inst!(I32TruncSatF64U, (f64) -> i32, |c| c.config.saturating_float_to_int_enabled),338inst!(I64TruncSatF32S, (f32) -> i64, |c| c.config.saturating_float_to_int_enabled),339inst!(I64TruncSatF32U, (f32) -> i64, |c| c.config.saturating_float_to_int_enabled),340inst!(I64TruncSatF64S, (f64) -> i64, |c| c.config.saturating_float_to_int_enabled),341inst!(I64TruncSatF64U, (f64) -> i64, |c| c.config.saturating_float_to_int_enabled),342inst!(I32ReinterpretF32, (f32) -> i32),343inst!(I64ReinterpretF64, (f64) -> i64),344// Floating-point conversions ("to float").345inst!(F32DemoteF64, (f64) -> f32),346inst!(F64PromoteF32, (f32) -> f64),347inst!(F32ConvertI32S, (i32) -> f32),348inst!(F32ConvertI32U, (i32) -> f32),349inst!(F32ConvertI64S, (i64) -> f32),350inst!(F32ConvertI64U, (i64) -> f32),351inst!(F64ConvertI32S, (i32) -> f64),352inst!(F64ConvertI32U, (i32) -> f64),353inst!(F64ConvertI64S, (i64) -> f64),354inst!(F64ConvertI64U, (i64) -> f64),355inst!(F32ReinterpretI32, (i32) -> f32),356inst!(F64ReinterpretI64, (i64) -> f64),357// SIMD instructions.358// V128Const359// I8x16Shuffle360inst!(I8x16Swizzle, (v128, v128) -> v128, |c| c.config.simd_enabled),361inst!(I8x16Splat, (i32) -> v128, |c| c.config.simd_enabled),362inst!(I16x8Splat, (i32) -> v128, |c| c.config.simd_enabled),363inst!(I32x4Splat, (i32) -> v128, |c| c.config.simd_enabled),364inst!(I64x2Splat, (i64) -> v128, |c| c.config.simd_enabled),365inst!(F32x4Splat, (f32) -> v128, |c| c.config.simd_enabled),366inst!(F64x2Splat, (f64) -> v128, |c| c.config.simd_enabled),367// I8x16ExtractLaneS368// I8x16ExtractLaneU369// I8x16ReplaceLane370// I16x8ExtractLaneS371// I16x8ExtractLaneU372// I16x8ReplaceLane373// I32x4ExtractLane374// I32x4ReplaceLane375// I64x2ExtractLane376// I64x2ReplaceLane377// F32x4ExtractLane378// F32x4ReplaceLane379// F64x2ExtractLane380// F64x2ReplaceLane381inst!(I8x16Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),382inst!(I8x16Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),383inst!(I8x16LtS, (v128, v128) -> v128, |c| c.config.simd_enabled),384inst!(I8x16LtU, (v128, v128) -> v128, |c| c.config.simd_enabled),385inst!(I8x16GtS, (v128, v128) -> v128, |c| c.config.simd_enabled),386inst!(I8x16GtU, (v128, v128) -> v128, |c| c.config.simd_enabled),387inst!(I8x16LeS, (v128, v128) -> v128, |c| c.config.simd_enabled),388inst!(I8x16LeU, (v128, v128) -> v128, |c| c.config.simd_enabled),389inst!(I8x16GeS, (v128, v128) -> v128, |c| c.config.simd_enabled),390inst!(I8x16GeU, (v128, v128) -> v128, |c| c.config.simd_enabled),391inst!(I16x8Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),392inst!(I16x8Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),393inst!(I16x8LtS, (v128, v128) -> v128, |c| c.config.simd_enabled),394inst!(I16x8LtU, (v128, v128) -> v128, |c| c.config.simd_enabled),395inst!(I16x8GtS, (v128, v128) -> v128, |c| c.config.simd_enabled),396inst!(I16x8GtU, (v128, v128) -> v128, |c| c.config.simd_enabled),397inst!(I16x8LeS, (v128, v128) -> v128, |c| c.config.simd_enabled),398inst!(I16x8LeU, (v128, v128) -> v128, |c| c.config.simd_enabled),399inst!(I16x8GeS, (v128, v128) -> v128, |c| c.config.simd_enabled),400inst!(I16x8GeU, (v128, v128) -> v128, |c| c.config.simd_enabled),401inst!(I32x4Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),402inst!(I32x4Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),403inst!(I32x4LtS, (v128, v128) -> v128, |c| c.config.simd_enabled),404inst!(I32x4LtU, (v128, v128) -> v128, |c| c.config.simd_enabled),405inst!(I32x4GtS, (v128, v128) -> v128, |c| c.config.simd_enabled),406inst!(I32x4GtU, (v128, v128) -> v128, |c| c.config.simd_enabled),407inst!(I32x4LeS, (v128, v128) -> v128, |c| c.config.simd_enabled),408inst!(I32x4LeU, (v128, v128) -> v128, |c| c.config.simd_enabled),409inst!(I32x4GeS, (v128, v128) -> v128, |c| c.config.simd_enabled),410inst!(I32x4GeU, (v128, v128) -> v128, |c| c.config.simd_enabled),411inst!(I64x2Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),412inst!(I64x2Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),413inst!(I64x2LtS, (v128, v128) -> v128, |c| c.config.simd_enabled),414inst!(I64x2GtS, (v128, v128) -> v128, |c| c.config.simd_enabled),415inst!(I64x2LeS, (v128, v128) -> v128, |c| c.config.simd_enabled),416inst!(I64x2GeS, (v128, v128) -> v128, |c| c.config.simd_enabled),417inst!(F32x4Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),418inst!(F32x4Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),419inst!(F32x4Lt, (v128, v128) -> v128, |c| c.config.simd_enabled),420inst!(F32x4Gt, (v128, v128) -> v128, |c| c.config.simd_enabled),421inst!(F32x4Le, (v128, v128) -> v128, |c| c.config.simd_enabled),422inst!(F32x4Ge, (v128, v128) -> v128, |c| c.config.simd_enabled),423inst!(F64x2Eq, (v128, v128) -> v128, |c| c.config.simd_enabled),424inst!(F64x2Ne, (v128, v128) -> v128, |c| c.config.simd_enabled),425inst!(F64x2Lt, (v128, v128) -> v128, |c| c.config.simd_enabled),426inst!(F64x2Gt, (v128, v128) -> v128, |c| c.config.simd_enabled),427inst!(F64x2Le, (v128, v128) -> v128, |c| c.config.simd_enabled),428inst!(F64x2Ge, (v128, v128) -> v128, |c| c.config.simd_enabled),429inst!(V128Not, (v128) -> v128, |c| c.config.simd_enabled),430inst!(V128And, (v128, v128) -> v128, |c| c.config.simd_enabled),431inst!(V128AndNot, (v128, v128) -> v128, |c| c.config.simd_enabled),432inst!(V128Or, (v128, v128) -> v128, |c| c.config.simd_enabled),433inst!(V128Xor, (v128, v128) -> v128, |c| c.config.simd_enabled),434inst!(V128Bitselect, (v128, v128, v128) -> v128, |c| c.config.simd_enabled),435inst!(V128AnyTrue, (v128) -> i32, |c| c.config.simd_enabled),436inst!(I8x16Abs, (v128) -> v128, |c| c.config.simd_enabled),437inst!(I8x16Neg, (v128) -> v128, |c| c.config.simd_enabled),438inst!(I8x16Popcnt, (v128) -> v128, |c| c.config.simd_enabled),439inst!(I8x16AllTrue, (v128) -> i32, |c| c.config.simd_enabled),440inst!(I8x16Bitmask, (v128) -> i32, |c| c.config.simd_enabled),441inst!(I8x16NarrowI16x8S, (v128, v128) -> v128, |c| c.config.simd_enabled),442inst!(I8x16NarrowI16x8U, (v128, v128) -> v128, |c| c.config.simd_enabled),443inst!(I8x16Shl, (v128, i32) -> v128, |c| c.config.simd_enabled),444inst!(I8x16ShrS, (v128, i32) -> v128, |c| c.config.simd_enabled),445inst!(I8x16ShrU, (v128, i32) -> v128, |c| c.config.simd_enabled),446inst!(I8x16Add, (v128, v128) -> v128, |c| c.config.simd_enabled),447inst!(I8x16AddSatS, (v128, v128) -> v128, |c| c.config.simd_enabled),448inst!(I8x16AddSatU, (v128, v128) -> v128, |c| c.config.simd_enabled),449inst!(I8x16Sub, (v128, v128) -> v128, |c| c.config.simd_enabled),450inst!(I8x16SubSatS, (v128, v128) -> v128, |c| c.config.simd_enabled),451inst!(I8x16SubSatU, (v128, v128) -> v128, |c| c.config.simd_enabled),452inst!(I8x16MinS, (v128, v128) -> v128, |c| c.config.simd_enabled),453inst!(I8x16MinU, (v128, v128) -> v128, |c| c.config.simd_enabled),454inst!(I8x16MaxS, (v128, v128) -> v128, |c| c.config.simd_enabled),455inst!(I8x16MaxU, (v128, v128) -> v128, |c| c.config.simd_enabled),456inst!(I8x16AvgrU, (v128, v128) -> v128, |c| c.config.simd_enabled),457inst!(I16x8ExtAddPairwiseI8x16S, (v128) -> v128, |c| c.config.simd_enabled),458inst!(I16x8ExtAddPairwiseI8x16U, (v128) -> v128, |c| c.config.simd_enabled),459inst!(I16x8Abs, (v128) -> v128, |c| c.config.simd_enabled),460inst!(I16x8Neg, (v128) -> v128, |c| c.config.simd_enabled),461inst!(I16x8Q15MulrSatS, (v128, v128) -> v128, |c| c.config.simd_enabled),462inst!(I16x8AllTrue, (v128) -> i32, |c| c.config.simd_enabled),463inst!(I16x8Bitmask, (v128) -> i32, |c| c.config.simd_enabled),464inst!(I16x8NarrowI32x4S, (v128, v128) -> v128, |c| c.config.simd_enabled),465inst!(I16x8NarrowI32x4U, (v128, v128) -> v128, |c| c.config.simd_enabled),466inst!(I16x8ExtendLowI8x16S, (v128) -> v128, |c| c.config.simd_enabled),467inst!(I16x8ExtendHighI8x16S, (v128) -> v128, |c| c.config.simd_enabled),468inst!(I16x8ExtendLowI8x16U, (v128) -> v128, |c| c.config.simd_enabled),469inst!(I16x8ExtendHighI8x16U, (v128) -> v128, |c| c.config.simd_enabled),470inst!(I16x8Shl, (v128, i32) -> v128, |c| c.config.simd_enabled),471inst!(I16x8ShrS, (v128, i32) -> v128, |c| c.config.simd_enabled),472inst!(I16x8ShrU, (v128, i32) -> v128, |c| c.config.simd_enabled),473inst!(I16x8Add, (v128, v128) -> v128, |c| c.config.simd_enabled),474inst!(I16x8AddSatS, (v128, v128) -> v128, |c| c.config.simd_enabled),475inst!(I16x8AddSatU, (v128, v128) -> v128, |c| c.config.simd_enabled),476inst!(I16x8Sub, (v128, v128) -> v128, |c| c.config.simd_enabled),477inst!(I16x8SubSatS, (v128, v128) -> v128, |c| c.config.simd_enabled),478inst!(I16x8SubSatU, (v128, v128) -> v128, |c| c.config.simd_enabled),479inst!(I16x8Mul, (v128, v128) -> v128, |c| c.config.simd_enabled),480inst!(I16x8MinS, (v128, v128) -> v128, |c| c.config.simd_enabled),481inst!(I16x8MinU, (v128, v128) -> v128, |c| c.config.simd_enabled),482inst!(I16x8MaxS, (v128, v128) -> v128, |c| c.config.simd_enabled),483inst!(I16x8MaxU, (v128, v128) -> v128, |c| c.config.simd_enabled),484inst!(I16x8AvgrU, (v128, v128) -> v128, |c| c.config.simd_enabled),485inst!(I16x8ExtMulLowI8x16S, (v128, v128) -> v128, |c| c.config.simd_enabled),486inst!(I16x8ExtMulHighI8x16S, (v128, v128) -> v128, |c| c.config.simd_enabled),487inst!(I16x8ExtMulLowI8x16U, (v128, v128) -> v128, |c| c.config.simd_enabled),488inst!(I16x8ExtMulHighI8x16U, (v128, v128) -> v128, |c| c.config.simd_enabled),489inst!(I32x4ExtAddPairwiseI16x8S, (v128) -> v128, |c| c.config.simd_enabled),490inst!(I32x4ExtAddPairwiseI16x8U, (v128) -> v128, |c| c.config.simd_enabled),491inst!(I32x4Abs, (v128) -> v128, |c| c.config.simd_enabled),492inst!(I32x4Neg, (v128) -> v128, |c| c.config.simd_enabled),493inst!(I32x4AllTrue, (v128) -> i32, |c| c.config.simd_enabled),494inst!(I32x4Bitmask, (v128) -> i32, |c| c.config.simd_enabled),495inst!(I32x4ExtendLowI16x8S, (v128) -> v128, |c| c.config.simd_enabled),496inst!(I32x4ExtendHighI16x8S, (v128) -> v128, |c| c.config.simd_enabled),497inst!(I32x4ExtendLowI16x8U, (v128) -> v128, |c| c.config.simd_enabled),498inst!(I32x4ExtendHighI16x8U, (v128) -> v128, |c| c.config.simd_enabled),499inst!(I32x4Shl, (v128, i32) -> v128, |c| c.config.simd_enabled),500inst!(I32x4ShrS, (v128, i32) -> v128, |c| c.config.simd_enabled),501inst!(I32x4ShrU, (v128, i32) -> v128, |c| c.config.simd_enabled),502inst!(I32x4Add, (v128, v128) -> v128, |c| c.config.simd_enabled),503inst!(I32x4Sub, (v128, v128) -> v128, |c| c.config.simd_enabled),504inst!(I32x4Mul, (v128, v128) -> v128, |c| c.config.simd_enabled),505inst!(I32x4MinS, (v128, v128) -> v128, |c| c.config.simd_enabled),506inst!(I32x4MinU, (v128, v128) -> v128, |c| c.config.simd_enabled),507inst!(I32x4MaxS, (v128, v128) -> v128, |c| c.config.simd_enabled),508inst!(I32x4MaxU, (v128, v128) -> v128, |c| c.config.simd_enabled),509inst!(I32x4DotI16x8S, (v128, v128) -> v128, |c| c.config.simd_enabled),510inst!(I32x4ExtMulLowI16x8S, (v128, v128) -> v128, |c| c.config.simd_enabled),511inst!(I32x4ExtMulHighI16x8S, (v128, v128) -> v128, |c| c.config.simd_enabled),512inst!(I32x4ExtMulLowI16x8U, (v128, v128) -> v128, |c| c.config.simd_enabled),513inst!(I32x4ExtMulHighI16x8U, (v128, v128) -> v128, |c| c.config.simd_enabled),514inst!(I64x2Abs, (v128) -> v128, |c| c.config.simd_enabled),515inst!(I64x2Neg, (v128) -> v128, |c| c.config.simd_enabled),516inst!(I64x2AllTrue, (v128) -> i32, |c| c.config.simd_enabled),517inst!(I64x2Bitmask, (v128) -> i32, |c| c.config.simd_enabled),518inst!(I64x2ExtendLowI32x4S, (v128) -> v128, |c| c.config.simd_enabled),519inst!(I64x2ExtendHighI32x4S, (v128) -> v128, |c| c.config.simd_enabled),520inst!(I64x2ExtendLowI32x4U, (v128) -> v128, |c| c.config.simd_enabled),521inst!(I64x2ExtendHighI32x4U, (v128) -> v128, |c| c.config.simd_enabled),522inst!(I64x2Shl, (v128, i32) -> v128, |c| c.config.simd_enabled),523inst!(I64x2ShrS, (v128, i32) -> v128, |c| c.config.simd_enabled),524inst!(I64x2ShrU, (v128, i32) -> v128, |c| c.config.simd_enabled),525inst!(I64x2Add, (v128, v128) -> v128, |c| c.config.simd_enabled),526inst!(I64x2Sub, (v128, v128) -> v128, |c| c.config.simd_enabled),527inst!(I64x2Mul, (v128, v128) -> v128, |c| c.config.simd_enabled),528inst!(I64x2ExtMulLowI32x4S, (v128, v128) -> v128, |c| c.config.simd_enabled),529inst!(I64x2ExtMulHighI32x4S, (v128, v128) -> v128, |c| c.config.simd_enabled),530inst!(I64x2ExtMulLowI32x4U, (v128, v128) -> v128, |c| c.config.simd_enabled),531inst!(I64x2ExtMulHighI32x4U, (v128, v128) -> v128, |c| c.config.simd_enabled),532inst!(F32x4Ceil, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),533inst!(F32x4Floor, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),534inst!(F32x4Trunc, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),535inst!(F32x4Nearest, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),536inst!(F32x4Abs, (v128) -> v128, |c| c.config.simd_enabled),537inst!(F32x4Neg, (v128) -> v128, |c| c.config.simd_enabled),538inst!(F32x4Sqrt, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),539inst!(F32x4Add, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),540inst!(F32x4Sub, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),541inst!(F32x4Mul, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),542inst!(F32x4Div, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),543inst!(F32x4Min, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),544inst!(F32x4Max, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F32x4)),545inst!(F32x4PMin, (v128, v128) -> v128, |c| c.config.simd_enabled),546inst!(F32x4PMax, (v128, v128) -> v128, |c| c.config.simd_enabled),547inst!(F64x2Ceil, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),548inst!(F64x2Floor, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),549inst!(F64x2Trunc, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),550inst!(F64x2Nearest, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),551inst!(F64x2Abs, (v128) -> v128, |c| c.config.simd_enabled),552inst!(F64x2Neg, (v128) -> v128, |c| c.config.simd_enabled),553inst!(F64x2Sqrt, (v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),554inst!(F64x2Add, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),555inst!(F64x2Sub, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),556inst!(F64x2Mul, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),557inst!(F64x2Div, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),558inst!(F64x2Min, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),559inst!(F64x2Max, (v128, v128) -> v128, |c| c.config.simd_enabled, Some(NanType::F64x2)),560inst!(F64x2PMin, (v128, v128) -> v128, |c| c.config.simd_enabled),561inst!(F64x2PMax, (v128, v128) -> v128, |c| c.config.simd_enabled),562inst!(I32x4TruncSatF32x4S, (v128) -> v128, |c| c.config.simd_enabled),563inst!(I32x4TruncSatF32x4U, (v128) -> v128, |c| c.config.simd_enabled),564inst!(F32x4ConvertI32x4S, (v128) -> v128, |c| c.config.simd_enabled),565inst!(F32x4ConvertI32x4U, (v128) -> v128, |c| c.config.simd_enabled),566inst!(I32x4TruncSatF64x2SZero, (v128) -> v128, |c| c.config.simd_enabled),567inst!(I32x4TruncSatF64x2UZero, (v128) -> v128, |c| c.config.simd_enabled),568inst!(F64x2ConvertLowI32x4S, (v128) -> v128, |c| c.config.simd_enabled),569inst!(F64x2ConvertLowI32x4U, (v128) -> v128, |c| c.config.simd_enabled),570inst!(F32x4DemoteF64x2Zero, (v128) -> v128, |c| c.config.simd_enabled),571inst!(F64x2PromoteLowF32x4, (v128) -> v128, |c| c.config.simd_enabled),572// wide arithmetic573inst!(I64Add128, (i64, i64, i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),574inst!(I64Sub128, (i64, i64, i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),575inst!(I64MulWideS, (i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),576inst!(I64MulWideU, (i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),577];578579#[cfg(test)]580mod test {581use super::*;582583#[test]584fn sanity() {585let sut = SingleInstModule {586instruction: Instruction::I32Add,587parameters: &[ValType::I32, ValType::I32],588results: &[ValType::I32],589feature: |_| true,590canonicalize_nan: None,591};592let wasm = sut.to_bytes();593let wat = wasmprinter::print_bytes(wasm).unwrap();594assert_eq!(595wat,596r#"(module597(type (;0;) (func (param i32 i32) (result i32)))598(export "test" (func 0))599(func (;0;) (type 0) (param i32 i32) (result i32)600local.get 0601local.get 1602i32.add603)604)605"#606)607}608609#[test]610fn instructions_encode_to_valid_modules() {611for inst in INSTRUCTIONS {612assert!(wat::parse_bytes(&inst.to_bytes()).is_ok());613}614}615}616617618