==> tests/fuse.c <==1/* What fuses (local.get or a constant into the next plain instruction, two local.gets), what
2 * doesn't (across a branch target, into control, an i64 constant into a store), and the remapping
3 * of every branch target. */
4#include "mesh/check.h"
5#include "wasm/fuse.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10static wasm_fn_code code(const wasm_ins *ins, uint32_t n) {
11 wasm_fn_code c;
12 memset(&c, 0, sizeof c);
13 c.code = malloc(n * sizeof *ins);
14 memcpy(c.code, ins, n * sizeof *ins);
15 c.ncode = n;
16 return c;
17}
18
19int main(void) {
20 /* 0 local.get 1; 1 i32.const 5; 2 i32.add; 3 local.get 0; 4 local.get 1; 5 i32.load off 8;
21 * 6 BR_IF -> 1; 7 i64.const 9; 8 i64.store off 4; 9 local.get 2; 10 BR -> 9; 11 RETURN */
22 wasm_ins in[] = {{0x20, 0, 1, 0}, {0x41, 0, 0, 5}, {0x6a, 0, 0, 0}, {0x20, 0, 0, 0}, {0x20, 0, 1, 0},
23 {0x28, 0, 0, 8}, {WASM_INS_BR_IF, 0, 1, 0}, {0x42, 0, 0, 9}, {0x37, 0, 0, 4},
24 {0x20, 0, 2, 0}, {WASM_INS_BR, 0, 9, 0}, {WASM_INS_RETURN, 0, 0, 0}};
25 wasm_fn_code c = code(in, sizeof in / sizeof in[0]);
26 c.brs = malloc(sizeof *c.brs);
27 c.brs[0] = (wasm_br_entry){7, 0, 0};
28 c.nbrs = 1;
29 CHECK(wasm_fuse(&c));
30 /* local.get 1 | i32.const 5 is a branch target: no fusion across it, but const+add fuse. */
31 uint16_t want[] = {0x20, WASM_INS_I + 0x6a, WASM_INS_GET2, 0x28, WASM_INS_BR_IF, 0x42, 0x37, 0x20, WASM_INS_BR,
32 WASM_INS_RETURN};
33 CHECK_U(c.ncode, sizeof want / sizeof want[0]);
34 for (uint32_t k = 0; k < c.ncode && k < sizeof want / sizeof want[0]; k++) CHECK_U(c.code[k].op, want[k]);
35 CHECK_U(c.code[1].b, 5);
36 CHECK_U(c.code[2].a, 0);
37 CHECK_U(c.code[2].b, 1);
38 CHECK_U(c.code[3].b, 8);
39 CHECK_U(c.code[4].a, 1); /* still the fused const+add */
40 CHECK_U(c.code[8].a, 7); /* local.get 2, a target, kept whole */
41 CHECK_U(c.brs[0].target, 5); /* the i64.const */
42 free(c.code);
43 free(c.brs);
44 /* Loads take a local address and an i32.const address; stores a local value. */
45 wasm_ins m[] = {{0x20, 0, 3, 0}, {0x28, 0, 0, 16}, {0x41, 0, 0, 64}, {0x29, 0, 0, 8}, {0x20, 0, 4, 0},
46 {0x36, 0, 0, 12}, {WASM_INS_RETURN, 0, 0, 0}};
47 c = code(m, 7);
48 CHECK(wasm_fuse(&c));
49 CHECK_U(c.ncode, 4);
50 CHECK_U(c.code[0].op, WASM_INS_L + 0x28);
51 CHECK_U(c.code[0].a, 3);
52 CHECK_U(c.code[0].b, 16);
53 CHECK_U(c.code[1].op, WASM_INS_I + 0x29);
54 CHECK_U(c.code[1].a, 64);
55 CHECK_U(c.code[1].b, 8);
56 CHECK_U(c.code[2].op, WASM_INS_L + 0x36);
57 free(c.code);
58 CHECK(wasm_fusible(0x6a));
59 CHECK(wasm_fusible(0x100));
60 CHECK(!wasm_fusible(0x41));
61 CHECK(!wasm_fusible(0x3f));
62 CHECK(!wasm_fusible(WASM_INS_BR_IF));
63 CHECK(!wasm_fusible(0x20));
64 return mesh_check_done();
65}