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