ad-hack-binop-preamble.js (12561B)
1 // |jit-test| skip-if: true 2 3 // Common code to test simple binary operators. See runSimpleBinopTest below. 4 5 function expandConstantBinopInputs(op, memtype, inputs) { 6 let s = ''; 7 let ident = 0; 8 for ( let [a, b] of inputs ) { 9 let constlhs = `${memtype.layoutName} ${a.map(jsValueToWasmName).join(' ')}`; 10 let constrhs = `${memtype.layoutName} ${b.map(jsValueToWasmName).join(' ')}`; 11 s += ` 12 ;; lhs is constant, rhs is variable 13 (func (export "run_constlhs${ident}") 14 (v128.store (i32.const 0) 15 (call $doit_constlhs${ident} (v128.const ${constrhs})))) 16 (func $doit_constlhs${ident} (param $b v128) (result v128) 17 (${op} (v128.const ${constlhs}) (local.get $b))) 18 19 ;; rhs is constant, lhs is variable 20 (func (export "run_constrhs${ident}") 21 (v128.store (i32.const 0) 22 (call $doit_constrhs${ident} (v128.const ${constlhs})))) 23 (func $doit_constrhs${ident} (param $a v128) (result v128) 24 (${op} (local.get $a) (v128.const ${constrhs}))) 25 26 ;; both operands are constant 27 (func (export "run_constboth${ident}") 28 (v128.store (i32.const 0) 29 (call $doit_constboth${ident}))) 30 (func $doit_constboth${ident} (result v128) 31 (${op} (v128.const ${constlhs}) (v128.const ${constrhs})))` 32 ident++; 33 } 34 return s; 35 } 36 37 function insAndMemBinop(op, memtype, resultmemtype, inputs) { 38 var ins = wasmEvalText(` 39 (module 40 (memory (export "mem") 1 1) 41 42 ;; both arguments are variable 43 (func (export "run") 44 (v128.store (i32.const 0) 45 (call $doit (v128.load (i32.const 16)) (v128.load (i32.const 32))))) 46 (func $doit (param $a v128) (param $b v128) (result v128) 47 (${op} (local.get $a) (local.get $b))) 48 49 ${expandConstantBinopInputs(op, memtype, inputs)})`); 50 var mem = new memtype(ins.exports.mem.buffer); 51 var resultmem = !resultmemtype || memtype == resultmemtype ? mem : new resultmemtype(ins.exports.mem.buffer); 52 return [ins, mem, resultmem]; 53 } 54 55 function add(bits) { return (x, y) => sign_extend(x+y, bits) } 56 function add64(x, y) { return sign_extend(BigInt(x)+BigInt(y), 64) } 57 function sub(bits) { return (x, y) => sign_extend(x-y, bits) } 58 function sub64(x, y) { return sign_extend(BigInt(x)-BigInt(y), 64) } 59 // Even 32-bit multiply can overflow a Number, so always use BigInt 60 function mul(bits) { return (x, y) => sign_extend(BigInt(x)*BigInt(y), bits) } 61 function div(x, y) { return x/y } 62 function min(x, y) { return x < y ? x : y } 63 function max(x, y) { return x > y ? x : y } 64 function and(x, y) { return zero_extend(x&y, 8) } 65 function or(x, y) { return zero_extend(x|y, 8) } 66 function xor(x, y) { return zero_extend(x^y, 8) } 67 function andnot(x, y) { return zero_extend(x&~y, 8) } 68 function avgr(x, y) { return (x + y + 1) >> 1; } 69 function eq(truth) { return (x,y) => x==y ? truth : 0 } 70 function ne(truth) { return (x,y) => x!=y ? truth : 0 } 71 function lt(truth) { return (x, y) => x < y ? truth : 0 } 72 function gt(truth) { return (x, y) => x > y ? truth : 0 } 73 function le(truth) { return (x, y) => x <= y ? truth : 0 } 74 function ge(truth) { return (x, y) => x >= y ? truth : 0 } 75 76 function fadd(x, y) { return Math.fround(x+y) } 77 function fsub(x, y) { return Math.fround(x-y) } 78 function fmul(x, y) { return Math.fround(x*y) } 79 function fdiv(x, y) { return Math.fround(x/y) } 80 function fmin(x, y) { 81 if (x == y) return x; 82 if (x < y) return x; 83 if (y < x) return y; 84 if (isNaN(x)) return x; 85 return y; 86 } 87 function fmax(x, y) { 88 if (x == y) return x; 89 if (x > y) return x; 90 if (y > x) return y; 91 if (isNaN(x)) return x; 92 return y; 93 } 94 function dadd(x, y) { return x+y } 95 function dsub(x, y) { return x-y } 96 function dmul(x, y) { return x*y } 97 function ddiv(x, y) { return x/y } 98 var dmax = fmax; 99 var dmin = fmin; 100 101 function op_sat_s(bits, op) { 102 return (x, y) => { 103 return signed_saturate(op(sign_extend(x, bits), 104 sign_extend(y, bits)), 105 bits); 106 } 107 } 108 109 function op_sat_u(bits, op) { 110 return (x, y) => { 111 return unsigned_saturate(op(zero_extend(x, bits), 112 zero_extend(y, bits)), 113 bits); 114 } 115 } 116 117 function add_sat_s(bits) { 118 return op_sat_s(bits, (x,y) => x+y); 119 } 120 function sub_sat_s(bits) { 121 return op_sat_s(bits, (x,y) => x-y); 122 } 123 function add_sat_u(bits) { 124 return op_sat_u(bits, (x,y) => x+y); 125 } 126 function sub_sat_u(bits) { 127 return op_sat_u(bits, (x,y) => x-y); 128 } 129 130 function max_s(bits) { 131 return (x, y) => { 132 return sign_extend(max(sign_extend(x, bits), 133 sign_extend(y, bits)), 134 bits); 135 } 136 } 137 138 function min_s(bits) { 139 return (x, y) => { 140 return sign_extend(min(sign_extend(x, bits), 141 sign_extend(y, bits)), 142 bits); 143 } 144 } 145 146 function max_u(bits) { 147 return (x, y) => { 148 return max(zero_extend(x, bits), 149 zero_extend(y, bits)); 150 } 151 } 152 153 function min_u(bits) { 154 return (x, y) => { 155 return min(zero_extend(x, bits), 156 zero_extend(y, bits)); 157 } 158 } 159 160 function pmin(x, y) { return y < x ? y : x } 161 function pmax(x, y) { return x < y ? y : x } 162 163 assertEq(max_s(8)(1, 2), 2); 164 assertEq(max_s(8)(1, 128), 1); 165 assertEq(min_s(8)(1, 2), 1); 166 assertEq(min_s(8)(1, 128), -128); 167 assertEq(max_u(8)(1, 2), 2); 168 assertEq(max_u(8)(1, 128), 128); 169 assertEq(min_u(8)(1, 2), 1); 170 assertEq(min_u(8)(1, 128), 1); 171 172 var binopTests = 173 [['i8x16.add', Int8Array, add(8)], 174 ['i16x8.add', Int16Array, add(16)], 175 ['i32x4.add', Int32Array, add(32)], 176 ['i64x2.add', BigInt64Array, add64], 177 ['i8x16.sub', Int8Array, sub(8)], 178 ['i16x8.sub', Int16Array, sub(16)], 179 ['i32x4.sub', Int32Array, sub(32)], 180 ['i64x2.sub', BigInt64Array, sub64], 181 ['i8x16.add_sat_s', Int8Array, add_sat_s(8)], 182 ['i8x16.add_sat_u', Uint8Array, add_sat_u(8)], 183 ['i16x8.add_sat_s', Int16Array, add_sat_s(16)], 184 ['i16x8.add_sat_u', Uint16Array, add_sat_u(16)], 185 ['i8x16.sub_sat_s', Int8Array, sub_sat_s(8)], 186 ['i8x16.sub_sat_u', Uint8Array, sub_sat_u(8)], 187 ['i16x8.sub_sat_s', Int16Array, sub_sat_s(16)], 188 ['i16x8.sub_sat_u', Uint16Array, sub_sat_u(16)], 189 ['i16x8.mul', Int16Array, mul(16)], 190 ['i32x4.mul', Int32Array, mul(32)], 191 ['i64x2.mul', BigInt64Array, mul(64)], 192 ['i8x16.avgr_u', Uint8Array, avgr], 193 ['i16x8.avgr_u', Uint16Array, avgr], 194 ['i8x16.max_s', Int8Array, max_s(8)], 195 ['i8x16.max_u', Uint8Array, max_u(8)], 196 ['i8x16.min_s', Int8Array, min_s(8)], 197 ['i8x16.min_u', Uint8Array, min_u(8)], 198 ['i16x8.max_s', Int16Array, max_s(16)], 199 ['i16x8.max_u', Uint16Array, max_u(16)], 200 ['i16x8.min_s', Int16Array, min_s(16)], 201 ['i16x8.min_u', Uint16Array, min_u(16)], 202 ['i32x4.max_s', Int32Array, max_s(32)], 203 ['i32x4.max_u', Uint32Array, max_u(32)], 204 ['i32x4.min_s', Int32Array, min_s(32)], 205 ['i32x4.min_u', Uint32Array, min_u(32)], 206 ['v128.and', Uint8Array, and], 207 ['v128.or', Uint8Array, or], 208 ['v128.xor', Uint8Array, xor], 209 ['v128.andnot', Uint8Array, andnot], 210 ['f32x4.add', Float32Array, fadd], 211 ['f32x4.sub', Float32Array, fsub], 212 ['f32x4.mul', Float32Array, fmul], 213 ['f32x4.div', Float32Array, fdiv], 214 ['f32x4.min', Float32Array, fmin], 215 ['f32x4.max', Float32Array, fmax], 216 ['f64x2.add', Float64Array, dadd], 217 ['f64x2.sub', Float64Array, dsub], 218 ['f64x2.mul', Float64Array, dmul], 219 ['f64x2.div', Float64Array, ddiv], 220 ['f64x2.min', Float64Array, dmin], 221 ['f64x2.max', Float64Array, dmax], 222 ['i8x16.eq', Int8Array, eq(-1)], 223 ['i8x16.ne', Int8Array, ne(-1)], 224 ['i8x16.lt_s', Int8Array, lt(-1)], 225 ['i8x16.gt_s', Int8Array, gt(-1)], 226 ['i8x16.le_s', Int8Array, le(-1)], 227 ['i8x16.ge_s', Int8Array, ge(-1)], 228 ['i8x16.gt_u', Uint8Array, gt(0xFF)], 229 ['i8x16.ge_u', Uint8Array, ge(0xFF)], 230 ['i8x16.lt_u', Uint8Array, lt(0xFF)], 231 ['i8x16.le_u', Uint8Array, le(0xFF)], 232 ['i16x8.eq', Int16Array, eq(-1)], 233 ['i16x8.ne', Int16Array, ne(-1)], 234 ['i16x8.lt_s', Int16Array, lt(-1)], 235 ['i16x8.gt_s', Int16Array, gt(-1)], 236 ['i16x8.le_s', Int16Array, le(-1)], 237 ['i16x8.ge_s', Int16Array, ge(-1)], 238 ['i16x8.gt_u', Uint16Array, gt(0xFFFF)], 239 ['i16x8.ge_u', Uint16Array, ge(0xFFFF)], 240 ['i16x8.lt_u', Uint16Array, lt(0xFFFF)], 241 ['i16x8.le_u', Uint16Array, le(0xFFFF)], 242 ['i32x4.eq', Int32Array, eq(-1)], 243 ['i32x4.ne', Int32Array, ne(-1)], 244 ['i32x4.lt_s', Int32Array, lt(-1)], 245 ['i32x4.gt_s', Int32Array, gt(-1)], 246 ['i32x4.le_s', Int32Array, le(-1)], 247 ['i32x4.ge_s', Int32Array, ge(-1)], 248 ['i32x4.gt_u', Uint32Array, gt(0xFFFFFFFF)], 249 ['i32x4.ge_u', Uint32Array, ge(0xFFFFFFFF)], 250 ['i32x4.lt_u', Uint32Array, lt(0xFFFFFFFF)], 251 ['i32x4.le_u', Uint32Array, le(0xFFFFFFFF)], 252 ['f32x4.eq', Float32Array, eq(-1), Int32Array], 253 ['f32x4.ne', Float32Array, ne(-1), Int32Array], 254 ['f32x4.lt', Float32Array, lt(-1), Int32Array], 255 ['f32x4.gt', Float32Array, gt(-1), Int32Array], 256 ['f32x4.le', Float32Array, le(-1), Int32Array], 257 ['f32x4.ge', Float32Array, ge(-1), Int32Array], 258 ['f64x2.eq', Float64Array, eq(-1), BigInt64Array], 259 ['f64x2.ne', Float64Array, ne(-1), BigInt64Array], 260 ['f64x2.lt', Float64Array, lt(-1), BigInt64Array], 261 ['f64x2.gt', Float64Array, gt(-1), BigInt64Array], 262 ['f64x2.le', Float64Array, le(-1), BigInt64Array], 263 ['f64x2.ge', Float64Array, ge(-1), BigInt64Array], 264 ['f32x4.pmin', Float32Array, pmin], 265 ['f32x4.pmax', Float32Array, pmax], 266 ['f64x2.pmin', Float64Array, pmin], 267 ['f64x2.pmax', Float64Array, pmax]] 268 269 // Run v128 x v128 -> v128 tests. Inputs are taken from the common input sets, 270 // placed in memory, the test is run, and the result is extracted and checked. 271 // 272 // Runs tests with both operands as variables, either as constant, or both as 273 // constant. Also checks NaN behavior when appropriate. 274 // 275 // All runners that call this should use the same value for `ofParts` and should 276 // pass different values for `part`, up to `ofParts` - 1. 277 278 function runSimpleBinopTest(part, ofParts) { 279 let partSize = Math.ceil(binopTests.length / ofParts); 280 let start = part * partSize; 281 let end = Math.min((part + 1) * partSize, binopTests.length); 282 for ( let [op, memtype, rop, resultmemtype] of binopTests.slice(start, end) ) { 283 let inputs = cross(memtype.inputs); 284 let len = 16/memtype.BYTES_PER_ELEMENT; 285 let xs = iota(len); 286 let zero = xs.map(_ => 0); 287 let [ins, mem, resultmem] = insAndMemBinop(op, memtype, resultmemtype, inputs); 288 let bitsForF32 = memtype == Float32Array ? new Uint32Array(mem.buffer) : null; 289 let bitsForF64 = memtype == Float64Array ? new BigInt64Array(mem.buffer) : null; 290 291 function testIt(a,b,r) { 292 set(mem, len, a); 293 set(mem, len*2, b); 294 ins.exports.run(); 295 assertSame(get(resultmem, 0, len), r); 296 297 // Test signalling NaN superficially by replacing QNaN inputs with SNaN 298 if (bitsForF32 != null && (a.some(isNaN) || b.some(isNaN))) { 299 a.forEach((x, i) => { if (isNaN(x)) { bitsForF32[len+i] = 0x7FA0_0000; } }); 300 b.forEach((x, i) => { if (isNaN(x)) { bitsForF32[(len*2)+i] = 0x7FA0_0000; } }); 301 ins.exports.run(); 302 assertSame(get(resultmem, 0, len), r); 303 } 304 if (bitsForF64 != null && (a.some(isNaN) || b.some(isNaN))) { 305 a.forEach((x, i) => { if (isNaN(x)) { bitsForF64[len+i] = 0x7FF4_0000_0000_0000n; } }); 306 b.forEach((x, i) => { if (isNaN(x)) { bitsForF64[(len*2)+i] = 0x7FF4_0000_0000_0000n; } }); 307 ins.exports.run(); 308 assertSame(get(resultmem, 0, len), r); 309 } 310 } 311 312 function testConstIt(i,r) { 313 set(resultmem, 0, zero); 314 ins.exports["run_constlhs" + i](); 315 assertSame(get(resultmem, 0, len), r); 316 317 set(resultmem, 0, zero); 318 ins.exports["run_constrhs" + i](); 319 assertSame(get(resultmem, 0, len), r); 320 321 set(resultmem, 0, zero); 322 ins.exports["run_constboth" + i](); 323 assertSame(get(resultmem, 0, len), r); 324 } 325 326 let i = 0; 327 for (let [a,b] of inputs) { 328 let r = xs.map((i) => rop(a[i], b[i])); 329 testIt(a,b,r); 330 testConstIt(i,r); 331 i++; 332 } 333 } 334 }