binop-x64-ion-folding.js (7549B)
1 // |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration("x64") || getBuildConfiguration("simulator"); include:codegen-x64-test.js 2 3 // This file checks folding rules for wasm {and,or,xor}{32,64} on x64 via Ion. 4 // See also binop-x64-ion-codegen.js, which is similar. 5 6 // These tests check that a folding has happened. The function is also run 7 // and the result value checked. Note, many of the functions ignore one or 8 // both of their parameters. 9 // 10 // In many cases the expected code contains an unnecessary move via a 11 // temporary, generally e/rcx, for example: 12 // 13 // mov %rdi, %rcx 14 // mov %rcx, %rax 15 // 16 // where rdi is the first arg reg (on Linux) and rax is the retval reg. This 17 // is documented in bug 1701164. If/when that gets fixed, we will presumably 18 // have to redo the expected-outputs here. 19 // 20 // The situation is complicated further because many of the expected outputs 21 // here depend on one of the two argument registers, but they are different in 22 // the ELF ABI (rdi, rsi) and the Win64 ABI (rcx, rdx). For the latter case, 23 // the abovementioned spurious move from the first arg reg into rcx 24 // disappears. Hence there is some fudging using wildcards in register names, 25 // and `no_prefix`, to make the tests pass with both ABIs. 26 27 function test(ty, wasm_insn, must_appear, param0, param1, expected_result, 28 options = {}) { 29 let t = 30 `(module 31 (func (export "f") (param ${ty}) (param ${ty}) (result ${ty}) 32 ${wasm_insn} 33 ))`; 34 options.instanceBox = {value: null}; 35 codegenTestX64_adhoc(t, "f", must_appear, options); 36 let ins = options.instanceBox.value; 37 assertEq(ins.exports.f(param0, param1), expected_result); 38 } 39 40 function test32(wasm_insn, must_appear, param0, param1, expected_result, 41 options) { 42 return test('i32', wasm_insn, must_appear, param0, param1, expected_result, 43 options); 44 } 45 46 function test64(wasm_insn, must_appear, param0, param1, expected_result, 47 options) { 48 return test('i64', wasm_insn, must_appear, param0, param1, expected_result, 49 options); 50 } 51 52 // {AND,OR,XOR}{32,64} folding: both args const 53 54 test32('(i32.and (i32.const 0x12345678) (i32.const 0x0f0f0f0f))', 55 'mov \\$0x2040608, %eax', 56 0,0, 0x2040608); 57 test64('(i64.and (i64.const 0x1234567851505150) (i64.const 0x515051500f0f0f0f))', 58 'mov \\$0x1010505001000100, %rax', 59 0n,0n, 0x1010505001000100n); 60 61 test32('(i32.or (i32.const 0x12345678) (i32.const 0x0f0e0d0c))', 62 'mov \\$0x1F3E5F7C, %eax', 63 0,0, 0x1f3e5f7c); 64 test64('(i64.or (i64.const 0x1234567851505150) (i64.const 0x515051500f0f1337))', 65 'mov \\$0x537457785F5F5377, %rax', 66 0n,0n, 0x537457785f5f5377n); 67 68 test32('(i32.xor (i32.const 0x12345678) (i32.const 0x0f0e0d0c))', 69 'mov \\$0x1D3A5B74, %eax', 70 0,0, 0x1d3a5b74); 71 test64('(i64.xor (i64.const 0x1234567851505150) (i64.const 0x515051500f0f1337))', 72 'mov \\$0x436407285E5F4267, %rax', 73 0n,0n, 0x436407285e5f4267n); 74 75 // {AND,OR,XOR}{32,64} identities: first arg is all zeroes 76 77 test32('(i32.and (i32.const 0) (local.get 1))', 78 'xor %eax, %eax', 79 1234,5678, 0); 80 test64('(i64.and (i64.const 0) (local.get 1))', 81 'xor %eax, %eax', 82 1234n,5678n, 0n); 83 84 test32('(i32.or (i32.const 0) (local.get 1))', 85 `mov %e.., %ecx 86 mov %ecx, %eax`, 87 1234,5678, 5678); 88 test64('(i64.or (i64.const 0) (local.get 1))', 89 `mov %r.., %rcx 90 mov %rcx, %rax`, 91 1234n,5678n, 5678n); 92 93 test32('(i32.xor (i32.const 0) (local.get 1))', 94 `mov %e.., %ecx 95 mov %ecx, %eax`, 96 1234,5678, 5678); 97 test64('(i64.xor (i64.const 0) (local.get 1))', 98 `mov %r.., %rcx 99 mov %rcx, %rax`, 100 1234n,5678n, 5678n); 101 102 // {AND,OR,XOR}{32,64} identities: second arg is all zeroes 103 104 test32('(i32.and (local.get 0) (i32.const 0))', 105 'xor %eax, %eax', 106 1234,5678, 0); 107 test64('(i64.and (local.get 0) (i64.const 0))', 108 'xor %eax, %eax', 109 1234n,5678n, 0n); 110 111 test32('(i32.or (local.get 0) (i32.const 0))', 112 // mov %edi, %ecx -- expected on Linux but not on Windows 113 `mov %ecx, %eax`, 114 1234,5678, 1234, {no_prefix: true}); // required on Linux 115 test64('(i64.or (local.get 0) (i64.const 0))', 116 // mov %rdi, %rcx -- ditto 117 `mov %rcx, %rax`, 118 1234n,5678n, 1234n, {no_prefix: true}); 119 120 test32('(i32.xor (local.get 0) (i32.const 0))', 121 // mov %edi, %ecx -- ditto 122 `mov %ecx, %eax`, 123 1234,5678, 1234, {no_prefix: true}); 124 test64('(i64.xor (local.get 0) (i64.const 0))', 125 // mov %rdi, %rcx -- ditto 126 `mov %rcx, %rax`, 127 1234n,5678n, 1234n, {no_prefix: true}); 128 129 // {AND,OR,XOR}{32,64} identities: first arg is all ones 130 131 test32('(i32.and (i32.const 0xffffffff) (local.get 1))', 132 `mov %e.., %ecx 133 mov %ecx, %eax`, 134 1234,5678, 5678); 135 test64('(i64.and (i64.const 0xffffffffffffffff) (local.get 1))', 136 `mov %r.., %rcx 137 mov %rcx, %rax`, 138 1234n,5678n, 5678n); 139 140 test32('(i32.or (i32.const 0xffffffff) (local.get 1))', 141 'mov \\$-0x01, %eax', 142 1234,5678, -1/*0xffffffff*/); 143 test64('(i64.or (i64.const 0xffffffffffffffff) (local.get 1))', 144 'mov \\$-0x01, %rax', 145 1234n,5678n, -1n/*0xffffffffffffffff*/); 146 147 test32('(i32.xor (i32.const 0xffffffff) (local.get 1))', 148 `mov %e.., %ecx 149 mov %ecx, %eax 150 not %eax`, 151 1234,5678, -5679); 152 test64('(i64.xor (i64.const 0xffffffffffffffff) (local.get 1))', 153 `mov %r.., %rcx 154 mov %rcx, %rax 155 not %rax`, 156 1234n,5678n, -5679n); 157 158 // {AND,OR,XOR}{32,64} identities: second arg is all ones 159 160 test32('(i32.and (local.get 0) (i32.const 0xffffffff))', 161 // mov %edi, %ecx -- expected on Linux but not on Windows 162 `mov %ecx, %eax`, 163 1234,5678, 1234, {no_prefix: true}); // required on Linux 164 test64('(i64.and (local.get 0) (i64.const 0xffffffffffffffff))', 165 // mov %rdi, %rcx -- ditto 166 `mov %rcx, %rax`, 167 1234n,5678n, 1234n, {no_prefix: true}); 168 169 test32('(i32.or (local.get 0) (i32.const 0xffffffff))', 170 'mov \\$-0x01, %eax', 171 1234,5678, -1/*0xffffffff*/); 172 test64('(i64.or (local.get 0) (i64.const 0xffffffffffffffff))', 173 'mov \\$-0x01, %rax', 174 1234n,5678n, -1n/*0xffffffffffffffff*/); 175 176 test32('(i32.xor (local.get 0) (i32.const 0xffffffff))', 177 // mov %edi, %ecx -- ditto 178 `mov %ecx, %eax 179 not %eax`, 180 1234,5678, -1235, {no_prefix: true}); 181 test64('(i64.xor (local.get 0) (i64.const 0xffffffffffffffff))', 182 // mov %rdi, %rcx -- ditto 183 `mov %rcx, %rax 184 not %rax`, 185 1234n,5678n, -1235n, {no_prefix: true}); 186 187 // {AND,OR,XOR}{32,64} identities: both args the same 188 189 test32('(i32.and (local.get 0) (local.get 0))', 190 // mov %edi, %ecx -- ditto 191 `mov %ecx, %eax`, 192 1234,5678, 1234, {no_prefix: true}); 193 test64('(i64.and (local.get 0) (local.get 0))', 194 // mov %rdi, %rcx -- ditto 195 `mov %rcx, %rax`, 196 1234n,5678n, 1234n, {no_prefix: true}); 197 198 test32('(i32.or (local.get 0) (local.get 0))', 199 // mov %edi, %ecx -- ditto 200 `mov %ecx, %eax`, 201 1234,5678, 1234, {no_prefix: true}); 202 test64('(i64.or (local.get 0) (local.get 0))', 203 // mov %rdi, %rcx -- ditto 204 `mov %rcx, %rax`, 205 1234n,5678n, 1234n, {no_prefix: true}); 206 207 test32('(i32.xor (local.get 0) (local.get 0))', 208 'xor %eax, %eax', 209 1234,5678, 0); 210 test64('(i64.xor (local.get 0) (local.get 0))', 211 'xor %eax, %eax', 212 1234n,5678n, 0n);