summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/tail-calls/litmus11.js
blob: 78c7cd4c495af325336328a7be9b7b55bac8072f (plain)
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
// |jit-test| skip-if: !wasmTailCallsEnabled()

// Once we exhaust the register arguments this will alternately grow and then
// shrink the stack frame across tail call boundaries because the increment of
// stack allocation is 16 bytes and our variability exceeds that.
//
// (This is not redundant with eg litmus0, because in that case all the
// functions have the same ballast.  Here we have different ballast, so we get growing and
// shrinking.)
//
// See litmus13 for the same-module call_indirect case.
// See litmus16 for the cross-module call_indirect case.

function ntimes(n, v) {
    if (typeof v == "function")
        return iota(n).map(v).join(' ');
    return iota(n).map(_ => v).join(' ');
}

function get_local(n) {
    return `(local.get ${n})`
}

function compute(ballast) {
    return iota(ballast).reduce((p,g,n) => `(i32.or ${p} (local.get ${n}))`,
                                `(i32.const ${1 << ballast})`)
}

function build(n, ballast) {
    switch (n) {
    case 0:
        return `
(func $f0 (export "f") (result i32)
  (return_call $f1 (i32.const ${1 << n})))
`;
    case ballast:
        return `
(func $f${ballast} (param ${ntimes(ballast, 'i32')}) (result i32)
    (if (result i32) (i32.eqz (global.get $glob))
        (then (return ${compute(ballast)}))
        (else (block (result i32)
          (global.set $glob (i32.sub (global.get $glob) (i32.const 1)))
          (return_call $f0)))))
`;
    default:
        return `
(func $f${n} (param ${ntimes(n, 'i32')}) (result i32)
  (return_call $f${n+1} (i32.const ${1 << n}) ${ntimes(n, get_local)}))
`
    }
}

for ( let ballast=1; ballast < TailCallBallast; ballast++ ) {

    let vals = iota(ballast+1).map(v => 1 << v);
    let sumv = vals.reduce((p,c) => p|c);
    let text = `
(module
  (global $glob (mut i32) (i32.const ${TailCallIterations}))
  ${ntimes(ballast, n => build(n, ballast))}
  ${build(ballast, ballast)})
`;

    let ins = wasmEvalText(text);
    assertEq(ins.exports.f(), sumv);
}