skip to content
==> 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}