summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/binop-x64-ion-folding.js
blob: b291077d17264758b79d2e1a1e6121986e0ae860 (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
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
// |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration("x64") || getBuildConfiguration("simulator"); include:codegen-x64-test.js

// This file checks folding rules for wasm {and,or,xor}{32,64} on x64 via Ion.
// See also binop-x64-ion-codegen.js, which is similar.

// These tests check that a folding has happened.  The function is also run
// and the result value checked.  Note, many of the functions ignore one or
// both of their parameters.
//
// In many cases the expected code contains an unnecessary move via a
// temporary, generally e/rcx, for example:
//
//   mov %rdi, %rcx
//   mov %rcx, %rax
//
// where rdi is the first arg reg (on Linux) and rax is the retval reg.  This
// is documented in bug 1701164.  If/when that gets fixed, we will presumably
// have to redo the expected-outputs here.
//
// The situation is complicated further because many of the expected outputs
// here depend on one of the two argument registers, but they are different in
// the ELF ABI (rdi, rsi) and the Win64 ABI (rcx, rdx).  For the latter case,
// the abovementioned spurious move from the first arg reg into rcx
// disappears.  Hence there is some fudging using wildcards in register names,
// and `no_prefix`, to make the tests pass with both ABIs.

function test(ty, wasm_insn, must_appear, param0, param1, expected_result,
              options = {}) {
    let t =
        `(module
           (func (export "f") (param ${ty}) (param ${ty}) (result ${ty})
             ${wasm_insn}
        ))`;
    options.instanceBox = {value: null};
    codegenTestX64_adhoc(t, "f", must_appear, options);
    let ins = options.instanceBox.value;
    assertEq(ins.exports.f(param0, param1), expected_result);
}

function test32(wasm_insn, must_appear, param0, param1, expected_result,
                options) {
    return test('i32', wasm_insn, must_appear, param0, param1, expected_result,
                options);
}

function test64(wasm_insn, must_appear, param0, param1, expected_result,
                options) {
    return test('i64', wasm_insn, must_appear, param0, param1, expected_result,
               options);
}

// {AND,OR,XOR}{32,64} folding: both args const

test32('(i32.and (i32.const 0x12345678) (i32.const 0x0f0f0f0f))',
       'b8 08 06 04 02   mov \\$0x2040608, %eax',
       0,0, 0x2040608);
test64('(i64.and (i64.const 0x1234567851505150) (i64.const 0x515051500f0f0f0f))',
       '48 b8 00 01 00 01 50 50 10 10   mov \\$0x1010505001000100, %rax',
       0n,0n, 0x1010505001000100n);

test32('(i32.or (i32.const 0x12345678) (i32.const 0x0f0e0d0c))',
       'b8 7c 5f 3e 1f   mov \\$0x1F3E5F7C, %eax',
       0,0, 0x1f3e5f7c);
test64('(i64.or (i64.const 0x1234567851505150) (i64.const 0x515051500f0f1337))',
       '48 b8 77 53 5f 5f 78 57 74 53   mov \\$0x537457785F5F5377, %rax',
       0n,0n, 0x537457785f5f5377n);

test32('(i32.xor (i32.const 0x12345678) (i32.const 0x0f0e0d0c))',
       'b8 74 5b 3a 1d   mov \\$0x1D3A5B74, %eax',
       0,0, 0x1d3a5b74);
test64('(i64.xor (i64.const 0x1234567851505150) (i64.const 0x515051500f0f1337))',
       '48 b8 67 42 5f 5e 28 07 64 43   mov \\$0x436407285E5F4267, %rax',
       0n,0n, 0x436407285e5f4267n);

// {AND,OR,XOR}{32,64} identities: first arg is all zeroes

test32('(i32.and (i32.const 0) (local.get 1))',
       '33 c0   xor %eax, %eax',
       1234,5678, 0);
test64('(i64.and (i64.const 0) (local.get 1))',
       '33 c0   xor %eax, %eax',
       1234n,5678n, 0n);

test32('(i32.or (i32.const 0) (local.get 1))',
       `8b ..   mov %e.., %ecx
        8b c1   mov %ecx, %eax`,
       1234,5678, 5678);
test64('(i64.or (i64.const 0) (local.get 1))',
       `48 89 ..   mov %r.., %rcx
        48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 5678n);

test32('(i32.xor (i32.const 0) (local.get 1))',
       `8b ..   mov %e.., %ecx
        8b c1   mov %ecx, %eax`,
       1234,5678, 5678);
test64('(i64.xor (i64.const 0) (local.get 1))',
       `48 89 ..   mov %r.., %rcx
        48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 5678n);

// {AND,OR,XOR}{32,64} identities: second arg is all zeroes

test32('(i32.and (local.get 0) (i32.const 0))',
       '33 c0   xor %eax, %eax',
       1234,5678, 0);
test64('(i64.and (local.get 0) (i64.const 0))',
       '33 c0   xor %eax, %eax',
       1234n,5678n, 0n);

test32('(i32.or (local.get 0) (i32.const 0))',
     // 8b cf   mov %edi, %ecx  -- expected on Linux but not on Windows
       `8b c1   mov %ecx, %eax`,
       1234,5678, 1234, {no_prefix: true}); // required on Linux
test64('(i64.or (local.get 0) (i64.const 0))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 1234n, {no_prefix: true});

test32('(i32.xor (local.get 0) (i32.const 0))',
     // 8b cf   mov %edi, %ecx  -- ditto
       `8b c1   mov %ecx, %eax`,
       1234,5678, 1234, {no_prefix: true});
test64('(i64.xor (local.get 0) (i64.const 0))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 1234n, {no_prefix: true});

// {AND,OR,XOR}{32,64} identities: first arg is all ones

test32('(i32.and (i32.const 0xffffffff) (local.get 1))',
       `8b ..   mov %e.., %ecx
        8b c1   mov %ecx, %eax`,
       1234,5678, 5678);
test64('(i64.and (i64.const 0xffffffffffffffff) (local.get 1))',
       `48 89 ..   mov %r.., %rcx
        48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 5678n);

test32('(i32.or (i32.const 0xffffffff) (local.get 1))',
       'b8 ff ff ff ff   mov \\$-0x01, %eax',
       1234,5678, -1/*0xffffffff*/);
test64('(i64.or (i64.const 0xffffffffffffffff) (local.get 1))',
       '48 c7 c0 ff ff ff ff   mov \\$-0x01, %rax',
       1234n,5678n, -1n/*0xffffffffffffffff*/);

test32('(i32.xor (i32.const 0xffffffff) (local.get 1))',
       `8b ..   mov %e.., %ecx
        8b c1   mov %ecx, %eax
        f7 d0   not %eax`,
       1234,5678, -5679);
test64('(i64.xor (i64.const 0xffffffffffffffff) (local.get 1))',
       `48 89 ..   mov %r.., %rcx
        48 89 c8   mov %rcx, %rax
        48 f7 d0   not %rax`,
       1234n,5678n, -5679n);

// {AND,OR,XOR}{32,64} identities: second arg is all ones

test32('(i32.and (local.get 0) (i32.const 0xffffffff))',
     // 8b cf   mov %edi, %ecx  -- expected on Linux but not on Windows
       `8b c1   mov %ecx, %eax`,
       1234,5678, 1234, {no_prefix: true}); // required on Linux
test64('(i64.and (local.get 0) (i64.const 0xffffffffffffffff))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 1234n, {no_prefix: true});

test32('(i32.or (local.get 0) (i32.const 0xffffffff))',
       'b8 ff ff ff ff   mov \\$-0x01, %eax',
       1234,5678, -1/*0xffffffff*/);
test64('(i64.or (local.get 0) (i64.const 0xffffffffffffffff))',
       '48 c7 c0 ff ff ff ff   mov \\$-0x01, %rax',
       1234n,5678n, -1n/*0xffffffffffffffff*/);

test32('(i32.xor (local.get 0) (i32.const 0xffffffff))',
     // 8b cf   mov %edi, %ecx  -- ditto
       `8b c1   mov %ecx, %eax
        f7 d0   not %eax`,
       1234,5678, -1235, {no_prefix: true});
test64('(i64.xor (local.get 0) (i64.const 0xffffffffffffffff))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax
        48 f7 d0   not %rax`,
       1234n,5678n, -1235n, {no_prefix: true});

// {AND,OR,XOR}{32,64} identities: both args the same

test32('(i32.and (local.get 0) (local.get 0))',
     // 8b cf   mov %edi, %ecx  -- ditto
       `8b c1   mov %ecx, %eax`,
       1234,5678, 1234, {no_prefix: true});
test64('(i64.and (local.get 0) (local.get 0))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 1234n, {no_prefix: true});

test32('(i32.or (local.get 0) (local.get 0))',
     // 8b cf   mov %edi, %ecx  -- ditto
       `8b c1   mov %ecx, %eax`,
       1234,5678, 1234, {no_prefix: true});
test64('(i64.or (local.get 0) (local.get 0))',
     // 48 89 f9   mov %rdi, %rcx  -- ditto
       `48 89 c8   mov %rcx, %rax`,
       1234n,5678n, 1234n, {no_prefix: true});

test32('(i32.xor (local.get 0) (local.get 0))',
       '33 c0   xor %eax, %eax',
       1234,5678, 0);
test64('(i64.xor (local.get 0) (local.get 0))',
       '33 c0   xor %eax, %eax',
       1234n,5678n, 0n);