wasmi 0.36.0

WebAssembly interpreter
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
use super::{wasm_type::WasmTy, *};
use crate::{
    core::ValType,
    engine::bytecode::{BranchOffset, BranchOffset16, GlobalIdx},
};
use std::fmt::{Debug, Display};

#[test]
#[cfg_attr(miri, ignore)]
fn loop_backward() {
    fn test_for(
        ty: ValType,
        op: &str,
        expect_instr: fn(Register, Register, BranchOffset16) -> Instruction,
    ) {
        let ty = DisplayValueType::from(ty);
        let wasm = format!(
            r"
            (module
                (func (param {ty} {ty})
                    (loop
                        (local.get 0)
                        (local.get 1)
                        ({ty}.{op})
                        (br_if 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(0),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for(ValType::I32, "and", Instruction::branch_i32_and);
    test_for(ValType::I32, "or", Instruction::branch_i32_or);
    test_for(ValType::I32, "xor", Instruction::branch_i32_xor);
    test_for(ValType::I32, "eq", Instruction::branch_i32_eq);
    test_for(ValType::I32, "ne", Instruction::branch_i32_ne);
    test_for(ValType::I32, "lt_s", Instruction::branch_i32_lt_s);
    test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u);
    test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s);
    test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u);
    test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s);
    test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u);
    test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s);
    test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u);

    test_for(ValType::I64, "eq", Instruction::branch_i64_eq);
    test_for(ValType::I64, "ne", Instruction::branch_i64_ne);
    test_for(ValType::I64, "lt_s", Instruction::branch_i64_lt_s);
    test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u);
    test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s);
    test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u);
    test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s);
    test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u);
    test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s);
    test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u);

    test_for(ValType::F32, "eq", Instruction::branch_f32_eq);
    test_for(ValType::F32, "ne", Instruction::branch_f32_ne);
    test_for(ValType::F32, "lt", Instruction::branch_f32_lt);
    test_for(ValType::F32, "le", Instruction::branch_f32_le);
    test_for(ValType::F32, "gt", Instruction::branch_f32_gt);
    test_for(ValType::F32, "ge", Instruction::branch_f32_ge);

    test_for(ValType::F64, "eq", Instruction::branch_f64_eq);
    test_for(ValType::F64, "ne", Instruction::branch_f64_ne);
    test_for(ValType::F64, "lt", Instruction::branch_f64_lt);
    test_for(ValType::F64, "le", Instruction::branch_f64_le);
    test_for(ValType::F64, "gt", Instruction::branch_f64_gt);
    test_for(ValType::F64, "ge", Instruction::branch_f64_ge);
}

#[test]
#[cfg_attr(miri, ignore)]
fn loop_backward_imm() {
    fn test_for<T>(
        op: &str,
        value: T,
        expect_instr: fn(Register, Const16<T>, BranchOffset16) -> Instruction,
    ) where
        T: WasmTy,
        Const16<T>: TryFrom<T> + Debug,
        DisplayWasm<T>: Display,
    {
        let ty = T::NAME;
        let display_value = DisplayWasm::from(value);
        let wasm = format!(
            r"
            (module
                (func (param {ty} {ty})
                    (loop
                        (local.get 0)
                        ({ty}.const {display_value})
                        ({ty}.{op})
                        (br_if 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    <Const16<T>>::try_from(value).ok().unwrap(),
                    BranchOffset16::from(0),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for::<i32>("and", 1, Instruction::branch_i32_and_imm);
    test_for::<i32>("or", 1, Instruction::branch_i32_or_imm);
    test_for::<i32>("xor", 1, Instruction::branch_i32_xor_imm);
    test_for::<i32>("eq", 1, Instruction::branch_i32_eq_imm);
    test_for::<i32>("ne", 1, Instruction::branch_i32_ne_imm);
    test_for::<i32>("lt_s", 1, Instruction::branch_i32_lt_s_imm);
    test_for::<u32>("lt_u", 1, Instruction::branch_i32_lt_u_imm);
    test_for::<i32>("le_s", 1, Instruction::branch_i32_le_s_imm);
    test_for::<u32>("le_u", 1, Instruction::branch_i32_le_u_imm);
    test_for::<i32>("gt_s", 1, Instruction::branch_i32_gt_s_imm);
    test_for::<u32>("gt_u", 1, Instruction::branch_i32_gt_u_imm);
    test_for::<i32>("ge_s", 1, Instruction::branch_i32_ge_s_imm);
    test_for::<u32>("ge_u", 1, Instruction::branch_i32_ge_u_imm);

    test_for::<i64>("eq", 1, Instruction::branch_i64_eq_imm);
    test_for::<i64>("ne", 1, Instruction::branch_i64_ne_imm);
    test_for::<i64>("lt_s", 1, Instruction::branch_i64_lt_s_imm);
    test_for::<u64>("lt_u", 1, Instruction::branch_i64_lt_u_imm);
    test_for::<i64>("le_s", 1, Instruction::branch_i64_le_s_imm);
    test_for::<u64>("le_u", 1, Instruction::branch_i64_le_u_imm);
    test_for::<i64>("gt_s", 1, Instruction::branch_i64_gt_s_imm);
    test_for::<u64>("gt_u", 1, Instruction::branch_i64_gt_u_imm);
    test_for::<i64>("ge_s", 1, Instruction::branch_i64_ge_s_imm);
    test_for::<u64>("ge_u", 1, Instruction::branch_i64_ge_u_imm);
}

#[test]
#[cfg_attr(miri, ignore)]
fn loop_backward_imm_eqz() {
    fn test_for(op: &str, expect_instr: fn(Register, BranchOffset16) -> Instruction) {
        let wasm = format!(
            r"
            (module
                (func (param i32 i32)
                    (loop
                        (local.get 0)
                        (i32.const 0)
                        (i32.{op})
                        (br_if 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(Register::from_i16(0), BranchOffset16::from(0_i16)),
                Instruction::Return,
            ])
            .run()
    }
    test_for("eq", Instruction::branch_i32_eqz);
    test_for("ne", Instruction::branch_i32_nez);
}

#[test]
#[cfg_attr(miri, ignore)]
fn block_forward() {
    fn test_for(
        ty: ValType,
        op: &str,
        expect_instr: fn(Register, Register, BranchOffset16) -> Instruction,
    ) {
        let ty = DisplayValueType::from(ty);
        let wasm = format!(
            r"
            (module
                (func (param {ty} {ty})
                    (block
                        (local.get 0)
                        (local.get 1)
                        ({ty}.{op})
                        (br_if 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(1),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for(ValType::I32, "and", Instruction::branch_i32_and);
    test_for(ValType::I32, "or", Instruction::branch_i32_or);
    test_for(ValType::I32, "xor", Instruction::branch_i32_xor);
    test_for(ValType::I32, "eq", Instruction::branch_i32_eq);
    test_for(ValType::I32, "ne", Instruction::branch_i32_ne);
    test_for(ValType::I32, "lt_s", Instruction::branch_i32_lt_s);
    test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u);
    test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s);
    test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u);
    test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s);
    test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u);
    test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s);
    test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u);

    test_for(ValType::I64, "eq", Instruction::branch_i64_eq);
    test_for(ValType::I64, "ne", Instruction::branch_i64_ne);
    test_for(ValType::I64, "lt_s", Instruction::branch_i64_lt_s);
    test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u);
    test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s);
    test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u);
    test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s);
    test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u);
    test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s);
    test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u);

    test_for(ValType::F32, "eq", Instruction::branch_f32_eq);
    test_for(ValType::F32, "ne", Instruction::branch_f32_ne);
    test_for(ValType::F32, "lt", Instruction::branch_f32_lt);
    test_for(ValType::F32, "le", Instruction::branch_f32_le);
    test_for(ValType::F32, "gt", Instruction::branch_f32_gt);
    test_for(ValType::F32, "ge", Instruction::branch_f32_ge);

    test_for(ValType::F64, "eq", Instruction::branch_f64_eq);
    test_for(ValType::F64, "ne", Instruction::branch_f64_ne);
    test_for(ValType::F64, "lt", Instruction::branch_f64_lt);
    test_for(ValType::F64, "le", Instruction::branch_f64_le);
    test_for(ValType::F64, "gt", Instruction::branch_f64_gt);
    test_for(ValType::F64, "ge", Instruction::branch_f64_ge);
}

#[test]
#[cfg_attr(miri, ignore)]
fn block_forward_nop_copy() {
    fn test_for(
        ty: ValType,
        op: &str,
        expect_instr: fn(Register, Register, BranchOffset16) -> Instruction,
    ) {
        let ty = DisplayValueType::from(ty);
        let wasm = format!(
            r"
            (module
                (global $g (mut {ty}) ({ty}.const 10))
                (func (param {ty} {ty}) (result {ty})
                    (global.get $g)
                    (block (param {ty}) (result {ty})
                        (local.get 0)
                        (local.get 1)
                        ({ty}.{op})
                        (br_if 0)
                        (drop)
                        (local.get 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                Instruction::global_get(Register::from_i16(2), GlobalIdx::from(0)),
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(2),
                ),
                Instruction::copy(Register::from_i16(2), Register::from_i16(0)),
                Instruction::return_reg(2),
            ])
            .run()
    }

    test_for(ValType::I32, "and", Instruction::branch_i32_and);
    test_for(ValType::I32, "or", Instruction::branch_i32_or);
    test_for(ValType::I32, "xor", Instruction::branch_i32_xor);
    test_for(ValType::I32, "eq", Instruction::branch_i32_eq);
    test_for(ValType::I32, "ne", Instruction::branch_i32_ne);
    test_for(ValType::I32, "lt_s", Instruction::branch_i32_lt_s);
    test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u);
    test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s);
    test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u);
    test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s);
    test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u);
    test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s);
    test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u);

    test_for(ValType::I64, "eq", Instruction::branch_i64_eq);
    test_for(ValType::I64, "ne", Instruction::branch_i64_ne);
    test_for(ValType::I64, "lt_s", Instruction::branch_i64_lt_s);
    test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u);
    test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s);
    test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u);
    test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s);
    test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u);
    test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s);
    test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u);

    test_for(ValType::F32, "eq", Instruction::branch_f32_eq);
    test_for(ValType::F32, "ne", Instruction::branch_f32_ne);
    test_for(ValType::F32, "lt", Instruction::branch_f32_lt);
    test_for(ValType::F32, "le", Instruction::branch_f32_le);
    test_for(ValType::F32, "gt", Instruction::branch_f32_gt);
    test_for(ValType::F32, "ge", Instruction::branch_f32_ge);

    test_for(ValType::F64, "eq", Instruction::branch_f64_eq);
    test_for(ValType::F64, "ne", Instruction::branch_f64_ne);
    test_for(ValType::F64, "lt", Instruction::branch_f64_lt);
    test_for(ValType::F64, "le", Instruction::branch_f64_le);
    test_for(ValType::F64, "gt", Instruction::branch_f64_gt);
    test_for(ValType::F64, "ge", Instruction::branch_f64_ge);
}

#[test]
#[cfg_attr(miri, ignore)]
fn if_forward_multi_value() {
    fn test_for(
        ty: ValType,
        op: &str,
        expect_instr: fn(Register, Register, BranchOffset16) -> Instruction,
    ) {
        let ty = DisplayValueType::from(ty);
        let wasm = format!(
            r"
            (module
                (func (param {ty} {ty}) (result {ty})
                    (block (result {ty})
                        (local.get 0) ;; returned from block if `local.get 0 != 0`
                        (local.get 0)
                        (local.get 1)
                        ({ty}.{op})
                        (br_if 0)
                        (drop)
                        (local.get 1) ;; returned from block if `local.get 0 == 0`
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(3),
                ),
                Instruction::copy(Register::from_i16(2), Register::from_i16(0)),
                Instruction::branch(BranchOffset::from(2)),
                Instruction::copy(Register::from_i16(2), Register::from_i16(1)),
                Instruction::return_reg(2),
            ])
            .run()
    }

    test_for(ValType::I32, "and", Instruction::branch_i32_and_eqz);
    test_for(ValType::I32, "or", Instruction::branch_i32_or_eqz);
    test_for(ValType::I32, "xor", Instruction::branch_i32_xor_eqz);
    test_for(ValType::I32, "eq", Instruction::branch_i32_ne);
    test_for(ValType::I32, "ne", Instruction::branch_i32_eq);
    test_for(ValType::I32, "lt_s", Instruction::branch_i32_ge_s);
    test_for(ValType::I32, "lt_u", Instruction::branch_i32_ge_u);
    test_for(ValType::I32, "le_s", Instruction::branch_i32_gt_s);
    test_for(ValType::I32, "le_u", Instruction::branch_i32_gt_u);
    test_for(ValType::I32, "gt_s", Instruction::branch_i32_le_s);
    test_for(ValType::I32, "gt_u", Instruction::branch_i32_le_u);
    test_for(ValType::I32, "ge_s", Instruction::branch_i32_lt_s);
    test_for(ValType::I32, "ge_u", Instruction::branch_i32_lt_u);

    test_for(ValType::I64, "eq", Instruction::branch_i64_ne);
    test_for(ValType::I64, "ne", Instruction::branch_i64_eq);
    test_for(ValType::I64, "lt_s", Instruction::branch_i64_ge_s);
    test_for(ValType::I64, "lt_u", Instruction::branch_i64_ge_u);
    test_for(ValType::I64, "le_s", Instruction::branch_i64_gt_s);
    test_for(ValType::I64, "le_u", Instruction::branch_i64_gt_u);
    test_for(ValType::I64, "gt_s", Instruction::branch_i64_le_s);
    test_for(ValType::I64, "gt_u", Instruction::branch_i64_le_u);
    test_for(ValType::I64, "ge_s", Instruction::branch_i64_lt_s);
    test_for(ValType::I64, "ge_u", Instruction::branch_i64_lt_u);
}

#[test]
#[cfg_attr(miri, ignore)]
fn if_forward() {
    fn test_for(
        ty: ValType,
        op: &str,
        expect_instr: fn(Register, Register, BranchOffset16) -> Instruction,
    ) {
        let ty = DisplayValueType::from(ty);
        let wasm = format!(
            r"
            (module
                (func (param {ty} {ty})
                    (if
                        ({ty}.{op}
                            (local.get 0)
                            (local.get 1)
                        )
                        (then)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(1),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for(ValType::I32, "and", Instruction::branch_i32_and_eqz);
    test_for(ValType::I32, "or", Instruction::branch_i32_or_eqz);
    test_for(ValType::I32, "xor", Instruction::branch_i32_xor_eqz);
    test_for(ValType::I32, "eq", Instruction::branch_i32_ne);
    test_for(ValType::I32, "ne", Instruction::branch_i32_eq);
    test_for(ValType::I32, "lt_s", Instruction::branch_i32_ge_s);
    test_for(ValType::I32, "lt_u", Instruction::branch_i32_ge_u);
    test_for(ValType::I32, "le_s", Instruction::branch_i32_gt_s);
    test_for(ValType::I32, "le_u", Instruction::branch_i32_gt_u);
    test_for(ValType::I32, "gt_s", Instruction::branch_i32_le_s);
    test_for(ValType::I32, "gt_u", Instruction::branch_i32_le_u);
    test_for(ValType::I32, "ge_s", Instruction::branch_i32_lt_s);
    test_for(ValType::I32, "ge_u", Instruction::branch_i32_lt_u);

    test_for(ValType::I64, "eq", Instruction::branch_i64_ne);
    test_for(ValType::I64, "ne", Instruction::branch_i64_eq);
    test_for(ValType::I64, "lt_s", Instruction::branch_i64_ge_s);
    test_for(ValType::I64, "lt_u", Instruction::branch_i64_ge_u);
    test_for(ValType::I64, "le_s", Instruction::branch_i64_gt_s);
    test_for(ValType::I64, "le_u", Instruction::branch_i64_gt_u);
    test_for(ValType::I64, "gt_s", Instruction::branch_i64_le_s);
    test_for(ValType::I64, "gt_u", Instruction::branch_i64_le_u);
    test_for(ValType::I64, "ge_s", Instruction::branch_i64_lt_s);
    test_for(ValType::I64, "ge_u", Instruction::branch_i64_lt_u);
}

#[test]
#[cfg_attr(miri, ignore)]
fn block_i32_eqz_fuse() {
    fn test_for(op: &str, expect_instr: fn(Register, Register, BranchOffset16) -> Instruction) {
        let wasm = format!(
            r"
            (module
                (func (param i32 i32)
                    (block
                        (local.get 0)
                        (local.get 1)
                        (i32.{op})
                        (i32.eqz)
                        (br_if 0)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(1),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for("and", Instruction::branch_i32_and_eqz);
    test_for("or", Instruction::branch_i32_or_eqz);
    test_for("xor", Instruction::branch_i32_xor_eqz);
}

#[test]
#[cfg_attr(miri, ignore)]
fn if_i32_eqz_fuse() {
    fn test_for(op: &str, expect_instr: fn(Register, Register, BranchOffset16) -> Instruction) {
        let wasm = format!(
            r"
            (module
                (func (param i32 i32)
                    (if
                        (i32.eqz (i32.{op} (local.get 0) (local.get 1)))
                        (then)
                    )
                )
            )",
        );
        TranslationTest::from_wat(&wasm)
            .expect_func_instrs([
                expect_instr(
                    Register::from_i16(0),
                    Register::from_i16(1),
                    BranchOffset16::from(1),
                ),
                Instruction::Return,
            ])
            .run()
    }

    test_for("and", Instruction::branch_i32_and);
    test_for("or", Instruction::branch_i32_or);
    test_for("xor", Instruction::branch_i32_xor);
}

#[test]
#[cfg_attr(miri, ignore)]
fn block_i64_eqz_fuse() {
    let wasm = r"
        (module
            (func (param i64)
                (block
                    (i64.eqz (local.get 0))
                    (br_if 0)
                )
            )
        )";
    TranslationTest::from_wat(wasm)
        .expect_func_instrs([
            Instruction::branch_i64_eqz(Register::from_i16(0), BranchOffset16::from(1)),
            Instruction::Return,
        ])
        .run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn if_i64_eqz_fuse() {
    let wasm = r"
        (module
            (func (param i64)
                (if
                    (i64.eqz (local.get 0))
                    (then)
                )
            )
        )";
    TranslationTest::from_wat(wasm)
        .expect_func_instrs([
            Instruction::branch_i64_nez(Register::from_i16(0), BranchOffset16::from(1)),
            Instruction::Return,
        ])
        .run()
}