ad-hack.js (63195B)
1 // |jit-test| skip-if: !wasmSimdEnabled() 2 3 // Ad-hoc test cases used during development. Generally these are ordered from 4 // easier toward harder. 5 // 6 // The test cases here are usually those that require some special processing. 7 // Simple binary operators (v128 x v128 -> v128) and unary operators (v128 -> 8 // v128) are tested in ad-hack-simple-binops*.js and ad-hack-simple-unops.js. 9 10 // Do not include this in the preamble, it must be loaded after lib/wasm.js 11 load(scriptdir + "ad-hack-preamble.js") 12 13 // v128.store 14 // oob store 15 // v128.const 16 17 for ( let offset of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) { 18 var ins = wasmEvalText(` 19 (module 20 (memory (export "mem") 1 1) 21 (func (export "f") (param $loc i32) 22 (v128.store offset=${offset} (local.get $loc) (v128.const i32x4 ${1+offset} 2 3 ${4+offset*2}))))`); 23 var mem8 = new Uint8Array(ins.exports.mem.buffer); 24 ins.exports.f(160); 25 assertSame(getUnaligned(mem8, 4, 160 + offset, 4), [1+offset, 2, 3, 4+offset*2]); 26 27 // OOB write should trap 28 assertErrorMessage(() => ins.exports.f(65536-15), 29 WebAssembly.RuntimeError, 30 /index out of bounds/) 31 32 // Ensure that OOB writes don't write anything: moved to simd-partial-oob-store.js 33 } 34 35 // v128.load 36 // oob load 37 // v128.store 38 // temp register 39 40 for ( let offset of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) { 41 var ins = wasmEvalText(` 42 (module 43 (memory (export "mem") 1 1) 44 (func (export "copy") (param $dest i32) (param $src i32) 45 (v128.store (local.get $dest) (v128.load offset=${offset} (local.get $src)))))`); 46 var mem32 = new Uint32Array(ins.exports.mem.buffer); 47 var mem8 = new Uint8Array(ins.exports.mem.buffer); 48 setUnaligned(mem8, 4, 4*4 + offset, [8+offset, 10, 12, 14+offset*2]); 49 ins.exports.copy(40*4, 4*4); 50 assertSame(get(mem32, 40, 4), [8+offset, 10, 12, 14+offset*2]); 51 assertErrorMessage(() => ins.exports.copy(40*4, 65536-15), 52 WebAssembly.RuntimeError, 53 /index out of bounds/); 54 } 55 56 // call [with register params] 57 // parameters [in registers] 58 // return [with register values] 59 // locals 60 // 61 // local.get 62 // local.set 63 // v128.const 64 // v128.store 65 66 var ins = wasmEvalText(` 67 (module 68 (memory (export "mem") 1 1) 69 (func $g (param $param v128) (result v128) 70 (local $tmp v128) 71 (local.set $tmp (local.get $param)) 72 (local.get $tmp)) 73 (func (export "f") 74 (v128.store (i32.const 160) (call $g (v128.const i32x4 1 2 3 4)))))`); 75 var mem = new Uint32Array(ins.exports.mem.buffer); 76 ins.exports.f(); 77 assertSame(get(mem, 40, 4), [1, 2, 3, 4]); 78 79 // Same test but with local.tee 80 81 var ins = wasmEvalText(` 82 (module 83 (memory (export "mem") 1 1) 84 (func $g (param $param v128) (result v128) 85 (local $tmp v128) 86 (local.tee $tmp (local.get $param))) 87 (func (export "f") 88 (v128.store (i32.const 160) (call $g (v128.const i32x4 1 2 3 4)))))`); 89 var mem = new Uint32Array(ins.exports.mem.buffer); 90 ins.exports.f(); 91 assertSame(get(mem, 40, 4), [1, 2, 3, 4]); 92 93 // Locals that end up on the stack. Try to create unaligned placement (in the 94 // baseline compiler anyway) by inserting i32 locals before or after and 95 // inbetween the v128 ones and by having so many locals that we run out of 96 // registers. 97 98 var nlocals = 64; 99 for ( let start of [0, 1]) { 100 let decl = ""; 101 let set = ""; 102 let sum = "(v128.const i32x4 0 0 0 0)"; 103 var res = [0,0,0,0]; 104 var locno = start; 105 for ( let i=start ; i < start + nlocals ; i++ ) { 106 decl += "(local v128) "; 107 set += `(local.set ${locno} (v128.const i32x4 ${i} ${i+1} ${i+2} ${i+3})) `; 108 sum = `(i32x4.add ${sum} (local.get ${locno}))`; 109 locno++; 110 res[0] += i; 111 res[1] += i+1; 112 res[2] += i+2; 113 res[3] += i+3; 114 if ((i % 5) == 3) { 115 decl += "(local i32) "; 116 locno++; 117 } 118 } 119 if (start) 120 decl = "(local i32) " + decl; 121 else 122 decl += "(local i32) "; 123 var ins = wasmEvalText(` 124 (module 125 (memory (export "mem") 1 1) 126 (func $g (result v128) 127 ${decl} 128 ${set} 129 ${sum}) 130 (func (export "f") 131 (v128.store (i32.const 160) (call $g))))`); 132 133 var mem = new Uint32Array(ins.exports.mem.buffer); 134 ins.exports.f(); 135 assertSame(get(mem, 40, 4), res); 136 } 137 138 // Ditto parameters. This is like the case above but values are passed rather 139 // than set. 140 // 141 // call 142 // call_indirect 143 144 var nlocals = 64; 145 for ( let start of [0, 1]) { 146 let decl = ""; 147 let pass = ""; 148 let sum = "(v128.const i32x4 0 0 0 0)"; 149 var res = [0,0,0,0]; 150 var locno = start; 151 for ( let i=start ; i < start + nlocals ; i++ ) { 152 decl += "(param v128) "; 153 pass += `(v128.const i32x4 ${i} ${i+1} ${i+2} ${i+3}) `; 154 sum = `(i32x4.add ${sum} (local.get ${locno}))`; 155 locno++; 156 res[0] += i; 157 res[1] += i+1; 158 res[2] += i+2; 159 res[3] += i+3; 160 if ((i % 5) == 3) { 161 decl += "(param i32) "; 162 pass += "(i32.const 0) "; 163 locno++; 164 } 165 } 166 if (start) { 167 decl = "(param i32) " + decl; 168 pass = "(i32.const 0) " + pass; 169 } else { 170 decl += "(param i32) "; 171 pass += "(i32.const 0) "; 172 } 173 var txt = ` 174 (module 175 (memory (export "mem") 1 1) 176 (type $t1 (func ${decl} (result v128))) 177 (table funcref (elem $h)) 178 (func $g ${decl} (result v128) 179 ${sum}) 180 (func (export "f1") 181 (v128.store (i32.const 160) (call $g ${pass}))) 182 (func $h ${decl} (result v128) 183 ${sum}) 184 (func (export "f2") 185 (v128.store (i32.const 512) (call_indirect (type $t1) ${pass} (i32.const 0)))))`; 186 var ins = wasmEvalText(txt); 187 188 var mem = new Uint32Array(ins.exports.mem.buffer); 189 ins.exports.f1(); 190 assertSame(get(mem, 40, 4), res); 191 ins.exports.f2(); 192 assertSame(get(mem, 128, 4), res); 193 } 194 195 // Widening integer dot product 196 197 var ins = wasmEvalText(` 198 (module 199 (memory (export "mem") 1 1) 200 (func (export "run") 201 (v128.store (i32.const 0) 202 (i32x4.dot_i16x8_s (v128.load (i32.const 16)) (v128.load (i32.const 32))))))`); 203 204 var xs = [5, 1, -4, 2, 20, -15, 12, 3]; 205 var ys = [6, 0, -7, 3, 8, -1, -3, 7]; 206 var ans = [xs[0]*ys[0] + xs[1]*ys[1], 207 xs[2]*ys[2] + xs[3]*ys[3], 208 xs[4]*ys[4] + xs[5]*ys[5], 209 xs[6]*ys[6] + xs[7]*ys[7]]; 210 211 var mem16 = new Int16Array(ins.exports.mem.buffer); 212 var mem32 = new Int32Array(ins.exports.mem.buffer); 213 set(mem16, 8, xs); 214 set(mem16, 16, ys); 215 ins.exports.run(); 216 var result = get(mem32, 0, 4); 217 assertSame(result, ans); 218 219 // Splat, with and without constants (different code paths in ion) 220 221 var ins = wasmEvalText(` 222 (module 223 (memory (export "mem") 1 1) 224 (func (export "splat_i8x16") (param $src i32) 225 (v128.store (i32.const 0) (i8x16.splat (local.get $src)))) 226 (func (export "csplat_i8x16") 227 (v128.store (i32.const 0) (i8x16.splat (i32.const 37)))) 228 (func (export "splat_i16x8") (param $src i32) 229 (v128.store (i32.const 0) (i16x8.splat (local.get $src)))) 230 (func (export "csplat_i16x8") 231 (v128.store (i32.const 0) (i16x8.splat (i32.const 1175)))) 232 (func (export "splat_i32x4") (param $src i32) 233 (v128.store (i32.const 0) (i32x4.splat (local.get $src)))) 234 (func (export "csplat_i32x4") 235 (v128.store (i32.const 0) (i32x4.splat (i32.const 127639)))) 236 (func (export "splat_i64x2") (param $src i64) 237 (v128.store (i32.const 0) (i64x2.splat (local.get $src)))) 238 (func (export "csplat_i64x2") 239 (v128.store (i32.const 0) (i64x2.splat (i64.const 0x1234_5678_4365)))) 240 (func (export "splat_f32x4") (param $src f32) 241 (v128.store (i32.const 0) (f32x4.splat (local.get $src)))) 242 (func (export "csplat_f32x4") 243 (v128.store (i32.const 0) (f32x4.splat (f32.const 9121.25)))) 244 (func (export "splat_f64x2") (param $src f64) 245 (v128.store (i32.const 0) (f64x2.splat (local.get $src)))) 246 (func (export "csplat_f64x2") 247 (v128.store (i32.const 0) (f64x2.splat (f64.const 26789.125)))) 248 )`); 249 250 var mem8 = new Uint8Array(ins.exports.mem.buffer); 251 ins.exports.splat_i8x16(3); 252 assertSame(get(mem8, 0, 16), iota(16).map(_=>3)); 253 ins.exports.csplat_i8x16(); 254 assertSame(get(mem8, 0, 16), iota(16).map(_=>37)); 255 256 var mem16 = new Uint16Array(ins.exports.mem.buffer); 257 ins.exports.splat_i16x8(976); 258 assertSame(get(mem16, 0, 8), iota(8).map(_=>976)); 259 ins.exports.csplat_i16x8(); 260 assertSame(get(mem16, 0, 8), iota(8).map(_=>1175)); 261 262 var mem32 = new Uint32Array(ins.exports.mem.buffer); 263 ins.exports.splat_i32x4(147812); 264 assertSame(get(mem32, 0, 4), [147812, 147812, 147812, 147812]); 265 ins.exports.csplat_i32x4(); 266 assertSame(get(mem32, 0, 4), [127639, 127639, 127639, 127639]); 267 268 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 269 ins.exports.splat_i64x2(147812n); 270 assertSame(get(mem64, 0, 2), [147812, 147812]); 271 ins.exports.csplat_i64x2(); 272 assertSame(get(mem64, 0, 2), [0x1234_5678_4365n, 0x1234_5678_4365n]); 273 274 var memf32 = new Float32Array(ins.exports.mem.buffer); 275 ins.exports.splat_f32x4(147812.5); 276 assertSame(get(memf32, 0, 4), [147812.5, 147812.5, 147812.5, 147812.5]); 277 ins.exports.csplat_f32x4(); 278 assertSame(get(memf32, 0, 4), [9121.25, 9121.25, 9121.25, 9121.25]); 279 280 var memf64 = new Float64Array(ins.exports.mem.buffer); 281 ins.exports.splat_f64x2(147812.5); 282 assertSame(get(memf64, 0, 2), [147812.5, 147812.5]); 283 ins.exports.csplat_f64x2(); 284 assertSame(get(memf64, 0, 2), [26789.125, 26789.125]); 285 286 // AnyTrue. Ion constant folds, so test that too. 287 288 var ins = wasmEvalText(` 289 (module 290 (memory (export "mem") 1 1) 291 (func (export "anytrue_i8x16") (result i32) 292 (v128.any_true (v128.load (i32.const 16)))) 293 (func (export "true_anytrue_i8x16") (result i32) 294 (v128.any_true (v128.const i8x16 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0))) 295 (func (export "false_anytrue_i8x16") (result i32) 296 (v128.any_true (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))))`); 297 298 var mem = new Uint8Array(ins.exports.mem.buffer); 299 set(mem, 16, iota(16).map((_) => 0)); 300 assertEq(ins.exports.anytrue_i8x16(), 0); 301 302 for ( let dope of [1, 7, 32, 195 ] ) { 303 set(mem, 16, iota(16).map((x) => x == 7 ? dope : 0)); 304 assertEq(ins.exports.anytrue_i8x16(), 1); 305 } 306 307 assertEq(ins.exports.true_anytrue_i8x16(), 1); 308 assertEq(ins.exports.false_anytrue_i8x16(), 0); 309 310 // AllTrue. Ion constant folds, so test that too. 311 312 var ins = wasmEvalText(` 313 (module 314 (memory (export "mem") 1 1) 315 (func (export "alltrue_i8x16") (result i32) 316 (i8x16.all_true (v128.load (i32.const 16)))) 317 (func (export "true_alltrue_i8x16") (result i32) 318 (i8x16.all_true (v128.const i8x16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))) 319 (func (export "false_alltrue_i8x16") (result i32) 320 (i8x16.all_true (v128.const i8x16 1 2 3 4 5 6 0 8 9 10 11 12 13 14 15 16))) 321 (func (export "alltrue_i16x8") (result i32) 322 (i16x8.all_true (v128.load (i32.const 16)))) 323 (func (export "true_alltrue_i16x8") (result i32) 324 (i16x8.all_true (v128.const i16x8 1 2 3 4 5 6 7 8))) 325 (func (export "false_alltrue_i16x8") (result i32) 326 (i16x8.all_true (v128.const i16x8 1 2 3 4 5 0 7 8))) 327 (func (export "alltrue_i32x4") (result i32) 328 (i32x4.all_true (v128.load (i32.const 16)))) 329 (func (export "true_alltrue_i32x4") (result i32) 330 (i32x4.all_true (v128.const i32x4 1 2 3 4))) 331 (func (export "false_alltrue_i32x4") (result i32) 332 (i32x4.all_true (v128.const i32x4 1 2 3 0))))`); 333 334 var mem8 = new Uint8Array(ins.exports.mem.buffer); 335 var mem16 = new Uint16Array(ins.exports.mem.buffer); 336 var mem32 = new Uint32Array(ins.exports.mem.buffer); 337 338 set(mem8, 16, iota(16).map((_) => 0)); 339 assertEq(ins.exports.alltrue_i8x16(), 0); 340 assertEq(ins.exports.alltrue_i16x8(), 0); 341 assertEq(ins.exports.alltrue_i32x4(), 0); 342 343 set(mem8, 16, iota(16).map((_) => 1)); 344 assertEq(ins.exports.alltrue_i8x16(), 1); 345 346 set(mem16, 8, iota(8).map((_) => 1)); 347 assertEq(ins.exports.alltrue_i16x8(), 1); 348 349 set(mem32, 4, iota(4).map((_) => 1)); 350 assertEq(ins.exports.alltrue_i32x4(), 1); 351 352 for ( let dope of [1, 7, 32, 195 ] ) { 353 set(mem8, 16, iota(16).map((x) => x == 7 ? 0 : dope)); 354 assertEq(ins.exports.alltrue_i8x16(), 0); 355 356 set(mem16, 8, iota(8).map((x) => x == 4 ? 0 : dope)); 357 assertEq(ins.exports.alltrue_i16x8(), 0); 358 359 set(mem32, 4, iota(4).map((x) => x == 2 ? 0 : dope)); 360 assertEq(ins.exports.alltrue_i32x4(), 0); 361 } 362 363 assertEq(ins.exports.true_alltrue_i8x16(), 1); 364 assertEq(ins.exports.false_alltrue_i8x16(), 0); 365 assertEq(ins.exports.true_alltrue_i16x8(), 1); 366 assertEq(ins.exports.false_alltrue_i16x8(), 0); 367 assertEq(ins.exports.true_alltrue_i32x4(), 1); 368 assertEq(ins.exports.false_alltrue_i32x4(), 0); 369 370 // Bitmask. Ion constant folds, so test that too. 371 372 var ins = wasmEvalText(` 373 (module 374 (memory (export "mem") 1 1) 375 (func (export "bitmask_i8x16") (result i32) 376 (i8x16.bitmask (v128.load (i32.const 16)))) 377 (func (export "const_bitmask_i8x16") (result i32) 378 (i8x16.bitmask (v128.const i8x16 0x80 0x7f 0xff 0x33 0x42 0x98 0x01 0x00 379 0x31 0xcc 0xdd 0x12 0xf0 0x40 0x02 0xa0))) 380 (func (export "bitmask_i16x8") (result i32) 381 (i16x8.bitmask (v128.load (i32.const 16)))) 382 (func (export "const_bitmask_i16x8") (result i32) 383 (i16x8.bitmask (v128.const i16x8 0x7f80 0xff33 0x9842 0x0001 0xcc31 0x12dd 0x40f0 0xa002))) 384 (func (export "bitmask_i32x4") (result i32) 385 (i32x4.bitmask (v128.load (i32.const 16)))) 386 (func (export "const_bitmask_i32x4") (result i32) 387 (i32x4.bitmask (v128.const i32x4 0xff337f80 0x00019842 0xcc3112dd 0xa00240f0))))`); 388 389 var mem8 = new Uint8Array(ins.exports.mem.buffer); 390 var mem16 = new Uint16Array(ins.exports.mem.buffer); 391 var mem32 = new Uint32Array(ins.exports.mem.buffer); 392 393 set(mem8, 16, iota(16).map((_) => 0)); 394 assertEq(ins.exports.bitmask_i8x16(), 0); 395 assertEq(ins.exports.bitmask_i16x8(), 0); 396 assertEq(ins.exports.bitmask_i32x4(), 0); 397 398 set(mem8, 16, iota(16).map((_) => 0x80)); 399 assertEq(ins.exports.bitmask_i8x16(), 0xFFFF); 400 401 set(mem8, 16, iota(16).map((_) => 0x7F)); 402 assertEq(ins.exports.bitmask_i8x16(), 0); 403 404 set(mem8, 16, iota(16).map((i) => popcount(i) == 1 ? 0x80 : 0)); 405 assertEq(ins.exports.bitmask_i8x16(), (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8)); 406 407 assertEq(ins.exports.const_bitmask_i8x16(), 0x9625); 408 409 set(mem16, 8, iota(8).map((i) => 0x8000)) 410 assertEq(ins.exports.bitmask_i16x8(), 0xFF) 411 412 set(mem16, 8, iota(8).map((i) => 0x7FFF)) 413 assertEq(ins.exports.bitmask_i16x8(), 0) 414 415 set(mem16, 8, iota(8).map((i) => popcount(i) == 1 ? 0x8000 : 0)) 416 assertEq(ins.exports.bitmask_i16x8(), (1 << 1) | (1 << 2) | (1 << 4)); 417 418 assertEq(ins.exports.const_bitmask_i16x8(), 0x96); 419 420 set(mem32, 4, iota(4).map((_) => 0x80000000)) 421 assertEq(ins.exports.bitmask_i32x4(), 0xF); 422 423 set(mem32, 4, iota(4).map((_) => 0x7FFFFFFF)) 424 assertEq(ins.exports.bitmask_i32x4(), 0); 425 426 set(mem32, 4, iota(4).map((i) => popcount(i) == 1 ? 0x80000000 : 0)) 427 assertEq(ins.exports.bitmask_i32x4(), (1 << 1) | (1 << 2)); 428 429 assertEq(ins.exports.const_bitmask_i32x4(), 0xd); 430 431 // Shifts 432 // 433 // lhs is v128 in memory 434 // rhs is i32 (passed directly) 435 // result is v128 in memory 436 437 function shr(count, width) { 438 return (v) => { 439 if (count == 0) 440 return v; 441 if (width == 64) { 442 if (v < 0) { 443 // This basically mirrors what the SIMD code does, so if there's 444 // a bug there then there's a bug here too. Seems OK though. 445 let s = 0x1_0000_0000_0000_0000n + BigInt(v); 446 let t = s / (1n << BigInt(count)); 447 let u = ((1n << BigInt(count)) - 1n) * (2n ** BigInt(64-count)); 448 let w = t + u; 449 return w - 0x1_0000_0000_0000_0000n; 450 } 451 return BigInt(v) / (1n << BigInt(count)); 452 } else { 453 let mask = (width == 32) ? -1 : ((1 << width) - 1); 454 return (sign_extend(v, width) >> count) & mask; 455 } 456 } 457 } 458 459 function shru(count, width) { 460 if (width == 64) { 461 return (v) => { 462 if (count == 0) 463 return v; 464 if (v < 0) { 465 v = 0x1_0000_0000_0000_0000n + BigInt(v); 466 } 467 return BigInt(v) / (1n << BigInt(count)); 468 } 469 } else { 470 return (v) => { 471 let mask = (width == 32) ? -1 : ((1 << width) - 1); 472 return (v >>> count) & mask; 473 } 474 } 475 } 476 477 var constantI8Shifts = ""; 478 for ( let i of iota(10).concat([-7]) ) { 479 constantI8Shifts += ` 480 (func (export "shl_i8x16_${i}") 481 (v128.store (i32.const 0) (i8x16.shl (v128.load (i32.const 16)) (i32.const ${i})))) 482 (func (export "shr_i8x16_${i}") 483 (v128.store (i32.const 0) (i8x16.shr_s (v128.load (i32.const 16)) (i32.const ${i})))) 484 (func (export "shr_u8x16_${i}") 485 (v128.store (i32.const 0) (i8x16.shr_u (v128.load (i32.const 16)) (i32.const ${i}))))`; 486 } 487 488 var ins = wasmEvalText(` 489 (module 490 (memory (export "mem") 1 1) 491 (func (export "shl_i8x16") (param $count i32) 492 (v128.store (i32.const 0) (i8x16.shl (v128.load (i32.const 16)) (local.get $count)))) 493 (func (export "shr_i8x16") (param $count i32) 494 (v128.store (i32.const 0) (i8x16.shr_s (v128.load (i32.const 16)) (local.get $count)))) 495 (func (export "shr_u8x16") (param $count i32) 496 (v128.store (i32.const 0) (i8x16.shr_u (v128.load (i32.const 16)) (local.get $count)))) 497 ${constantI8Shifts} 498 (func (export "shl_i16x8") (param $count i32) 499 (v128.store (i32.const 0) (i16x8.shl (v128.load (i32.const 16)) (local.get $count)))) 500 (func (export "shl_i16x8_3") 501 (v128.store (i32.const 0) (i16x8.shl (v128.load (i32.const 16)) (i32.const 3)))) 502 (func (export "shl_i16x8_15") 503 (v128.store (i32.const 0) (i16x8.shl (v128.load (i32.const 16)) (i32.const 15)))) 504 (func (export "shl_i16x8_16") 505 (v128.store (i32.const 0) (i16x8.shl (v128.load (i32.const 16)) (i32.const 16)))) 506 (func (export "shl_i16x8_-15") 507 (v128.store (i32.const 0) (i16x8.shl (v128.load (i32.const 16)) (i32.const -15)))) 508 (func (export "shr_i16x8") (param $count i32) 509 (v128.store (i32.const 0) (i16x8.shr_s (v128.load (i32.const 16)) (local.get $count)))) 510 (func (export "shr_i16x8_3") 511 (v128.store (i32.const 0) (i16x8.shr_s (v128.load (i32.const 16)) (i32.const 3)))) 512 (func (export "shr_i16x8_15") 513 (v128.store (i32.const 0) (i16x8.shr_s (v128.load (i32.const 16)) (i32.const 15)))) 514 (func (export "shr_i16x8_16") 515 (v128.store (i32.const 0) (i16x8.shr_s (v128.load (i32.const 16)) (i32.const 16)))) 516 (func (export "shr_i16x8_-15") 517 (v128.store (i32.const 0) (i16x8.shr_s (v128.load (i32.const 16)) (i32.const -15)))) 518 (func (export "shr_u16x8") (param $count i32) 519 (v128.store (i32.const 0) (i16x8.shr_u (v128.load (i32.const 16)) (local.get $count)))) 520 (func (export "shr_u16x8_3") 521 (v128.store (i32.const 0) (i16x8.shr_u (v128.load (i32.const 16)) (i32.const 3)))) 522 (func (export "shr_u16x8_15") 523 (v128.store (i32.const 0) (i16x8.shr_u (v128.load (i32.const 16)) (i32.const 15)))) 524 (func (export "shr_u16x8_16") 525 (v128.store (i32.const 0) (i16x8.shr_u (v128.load (i32.const 16)) (i32.const 16)))) 526 (func (export "shr_u16x8_-15") 527 (v128.store (i32.const 0) (i16x8.shr_u (v128.load (i32.const 16)) (i32.const -15)))) 528 (func (export "shl_i32x4") (param $count i32) 529 (v128.store (i32.const 0) (i32x4.shl (v128.load (i32.const 16)) (local.get $count)))) 530 (func (export "shl_i32x4_12") 531 (v128.store (i32.const 0) (i32x4.shl (v128.load (i32.const 16)) (i32.const 12)))) 532 (func (export "shl_i32x4_31") 533 (v128.store (i32.const 0) (i32x4.shl (v128.load (i32.const 16)) (i32.const 31)))) 534 (func (export "shl_i32x4_32") 535 (v128.store (i32.const 0) (i32x4.shl (v128.load (i32.const 16)) (i32.const 32)))) 536 (func (export "shl_i32x4_-27") 537 (v128.store (i32.const 0) (i32x4.shl (v128.load (i32.const 16)) (i32.const -27)))) 538 (func (export "shr_i32x4") (param $count i32) 539 (v128.store (i32.const 0) (i32x4.shr_s (v128.load (i32.const 16)) (local.get $count)))) 540 (func (export "shr_i32x4_12") 541 (v128.store (i32.const 0) (i32x4.shr_s (v128.load (i32.const 16)) (i32.const 12)))) 542 (func (export "shr_i32x4_31") 543 (v128.store (i32.const 0) (i32x4.shr_s (v128.load (i32.const 16)) (i32.const 31)))) 544 (func (export "shr_i32x4_32") 545 (v128.store (i32.const 0) (i32x4.shr_s (v128.load (i32.const 16)) (i32.const 32)))) 546 (func (export "shr_i32x4_-27") 547 (v128.store (i32.const 0) (i32x4.shr_s (v128.load (i32.const 16)) (i32.const -27)))) 548 (func (export "shr_u32x4") (param $count i32) 549 (v128.store (i32.const 0) (i32x4.shr_u (v128.load (i32.const 16)) (local.get $count)))) 550 (func (export "shr_u32x4_12") 551 (v128.store (i32.const 0) (i32x4.shr_u (v128.load (i32.const 16)) (i32.const 12)))) 552 (func (export "shr_u32x4_31") 553 (v128.store (i32.const 0) (i32x4.shr_u (v128.load (i32.const 16)) (i32.const 31)))) 554 (func (export "shr_u32x4_32") 555 (v128.store (i32.const 0) (i32x4.shr_u (v128.load (i32.const 16)) (i32.const 32)))) 556 (func (export "shr_u32x4_-27") 557 (v128.store (i32.const 0) (i32x4.shr_u (v128.load (i32.const 16)) (i32.const -27)))) 558 (func (export "shl_i64x2") (param $count i32) 559 (v128.store (i32.const 0) (i64x2.shl (v128.load (i32.const 16)) (local.get $count)))) 560 (func (export "shl_i64x2_27") 561 (v128.store (i32.const 0) (i64x2.shl (v128.load (i32.const 16)) (i32.const 27)))) 562 (func (export "shl_i64x2_63") 563 (v128.store (i32.const 0) (i64x2.shl (v128.load (i32.const 16)) (i32.const 63)))) 564 (func (export "shl_i64x2_64") 565 (v128.store (i32.const 0) (i64x2.shl (v128.load (i32.const 16)) (i32.const 64)))) 566 (func (export "shl_i64x2_-231") 567 (v128.store (i32.const 0) (i64x2.shl (v128.load (i32.const 16)) (i32.const -231)))) 568 (func (export "shr_i64x2") (param $count i32) 569 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (local.get $count)))) 570 (func (export "shr_i64x2_27") 571 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const 27)))) 572 (func (export "shr_i64x2_45") 573 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const 45)))) 574 (func (export "shr_i64x2_63") 575 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const 63)))) 576 (func (export "shr_i64x2_64") 577 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const 64)))) 578 (func (export "shr_i64x2_-231") 579 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const -231)))) 580 (func (export "shr_i64x2_-1") 581 (v128.store (i32.const 0) (i64x2.shr_s (v128.load (i32.const 16)) (i32.const -1)))) 582 (func (export "shr_u64x2") (param $count i32) 583 (v128.store (i32.const 0) (i64x2.shr_u (v128.load (i32.const 16)) (local.get $count)))) 584 (func (export "shr_u64x2_27") 585 (v128.store (i32.const 0) (i64x2.shr_u (v128.load (i32.const 16)) (i32.const 27)))) 586 (func (export "shr_u64x2_63") 587 (v128.store (i32.const 0) (i64x2.shr_u (v128.load (i32.const 16)) (i32.const 63)))) 588 (func (export "shr_u64x2_64") 589 (v128.store (i32.const 0) (i64x2.shr_u (v128.load (i32.const 16)) (i32.const 64)))) 590 (func (export "shr_u64x2_-231") 591 (v128.store (i32.const 0) (i64x2.shr_u (v128.load (i32.const 16)) (i32.const -231)))))`); 592 593 var mem8 = new Uint8Array(ins.exports.mem.buffer); 594 var as = [1, 2, 4, 8, 16, 32, 64, 128, 129, 130, 132, 136, 144, 160, 192, 255]; 595 596 set(mem8, 16, as); 597 598 for (let [meth,op] of [["shl_i8x16",shl], ["shr_i8x16",shr], ["shr_u8x16",shru]]) { 599 for ( let i=0 ; i < 8 ; i++ ) { 600 ins.exports[meth](i); 601 assertSame(get(mem8, 0, 16), as.map(op(i, 8))) 602 ins.exports[meth + "_" + i](); 603 assertSame(get(mem8, 0, 16), as.map(op(i, 8))) 604 } 605 606 ins.exports[meth](1); 607 let a = get(mem8, 0, 16); 608 ins.exports[meth](9); 609 let b = get(mem8, 0, 16); 610 assertSame(a, b); 611 ins.exports[meth](-7); 612 let c = get(mem8, 0, 16); 613 assertSame(a, c); 614 615 ins.exports[meth + "_1"](); 616 let x = get(mem8, 0, 16); 617 ins.exports[meth + "_9"](); 618 let y = get(mem8, 0, 16); 619 ins.exports[meth + "_-7"](); 620 let z = get(mem8, 0, 16); 621 assertSame(x, y); 622 assertSame(x, z); 623 } 624 625 var mem16 = new Uint16Array(ins.exports.mem.buffer); 626 var as = [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000]; 627 set(mem16, 8, as) 628 629 ins.exports.shl_i16x8(2); 630 var res = get(mem16, 0, 8); 631 assertSame(res, as.map(shl(2, 16))) 632 633 ins.exports.shl_i16x8(18); // Masked count 634 assertSame(get(mem16, 0, 8), res); 635 636 ins.exports.shl_i16x8(-14); // Masked count 637 assertSame(get(mem16, 0, 8), res); 638 639 for ( let shift of [3, 15, 16, -15] ) { 640 ins.exports["shl_i16x8_" + shift](); 641 assertSame(get(mem16, 0, 8), as.map(shl(shift & 15, 16))) 642 } 643 644 ins.exports.shr_i16x8(1); 645 var res = get(mem16, 0, 8); 646 assertSame(res, as.map(shr(1, 16))) 647 648 ins.exports.shr_i16x8(17); // Masked count 649 assertSame(get(mem16, 0, 8), res); 650 651 ins.exports.shr_i16x8(-15); // Masked count 652 assertSame(get(mem16, 0, 8), res); 653 654 for ( let shift of [3, 15, 16, -15] ) { 655 ins.exports["shr_i16x8_" + shift](); 656 assertSame(get(mem16, 0, 8), as.map(shr(shift & 15, 16))) 657 } 658 659 ins.exports.shr_u16x8(1); 660 var res = get(mem16, 0, 8); 661 assertSame(res, as.map(shru(1, 16))) 662 663 ins.exports.shr_u16x8(17); // Masked count 664 assertSame(get(mem16, 0, 8), res); 665 666 ins.exports.shr_u16x8(-15); // Masked count 667 assertSame(get(mem16, 0, 8), res); 668 669 for ( let shift of [3, 15, 16, -15] ) { 670 ins.exports["shr_u16x8_" + shift](); 671 assertSame(get(mem16, 0, 8), as.map(shru(shift & 15, 16))) 672 } 673 674 var mem32 = new Uint32Array(ins.exports.mem.buffer); 675 var as = [5152, 6768, 7074, 800811]; 676 677 set(mem32, 4, as) 678 ins.exports.shl_i32x4(2); 679 var res = get(mem32, 0, 4); 680 assertSame(res, as.map(shl(2, 32))) 681 682 ins.exports.shl_i32x4(34); // Masked count 683 assertSame(get(mem32, 0, 4), res); 684 685 ins.exports.shl_i32x4(-30); // Masked count 686 assertSame(get(mem32, 0, 4), res); 687 688 for ( let shift of [12, 31, 32, -27] ) { 689 ins.exports["shl_i32x4_" + shift](); 690 assertSame(get(mem32, 0, 4), as.map(shl(shift & 31, 32)).map(x => x>>>0)) 691 } 692 693 ins.exports.shr_i32x4(1); 694 var res = get(mem32, 0, 4); 695 assertSame(res, as.map(shr(1, 32))) 696 697 ins.exports.shr_i32x4(33); // Masked count 698 assertSame(get(mem32, 0, 4), res); 699 700 ins.exports.shr_i32x4(-31); // Masked count 701 assertSame(get(mem32, 0, 4), res); 702 703 for ( let shift of [12, 31, 32, -27] ) { 704 ins.exports["shr_i32x4_" + shift](); 705 assertSame(get(mem32, 0, 4), as.map(shr(shift & 31, 32))) 706 } 707 708 ins.exports.shr_u32x4(1); 709 var res = get(mem32, 0, 4); 710 assertSame(res, as.map(shru(1, 32))) 711 712 ins.exports.shr_u32x4(33); // Masked count 713 assertSame(get(mem32, 0, 4), res); 714 715 ins.exports.shr_u32x4(-31); // Masked count 716 assertSame(get(mem32, 0, 4), res); 717 718 for ( let shift of [12, 31, 32, -27] ) { 719 ins.exports["shr_u32x4_" + shift](); 720 assertSame(get(mem32, 0, 4), as.map(shru(shift & 31, 32))) 721 } 722 723 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 724 var as = [50515253, -616263]; 725 726 set(mem64, 2, as) 727 ins.exports.shl_i64x2(2); 728 var res = get(mem64, 0, 2); 729 assertSame(res, as.map(shl(2, 64))) 730 731 ins.exports.shl_i64x2(66); // Masked count 732 assertSame(get(mem64, 0, 2), res); 733 734 ins.exports.shl_i64x2(-62); // Masked count 735 assertSame(get(mem64, 0, 2), res); 736 737 for ( let shift of [27, 63, 64, -231] ) { 738 ins.exports["shl_i64x2_" + shift](); 739 assertSame(get(mem64, 0, 2), as.map(shl(shift & 63, 64))) 740 } 741 742 ins.exports.shr_u64x2(1); 743 var res = get(mem64, 0, 2); 744 assertSame(res, as.map(shru(1, 64))) 745 746 ins.exports.shr_u64x2(65); // Masked count 747 assertSame(get(mem64, 0, 2), res); 748 749 ins.exports.shr_u64x2(-63); // Masked count 750 assertSame(get(mem64, 0, 2), res); 751 752 for ( let shift of [27, 63, 64, -231] ) { 753 ins.exports["shr_u64x2_" + shift](); 754 assertSame(get(mem64, 0, 2), as.map(shru(shift & 63, 64))) 755 } 756 757 ins.exports.shr_i64x2(2); 758 var res = get(mem64, 0, 2); 759 assertSame(res, as.map(shr(2, 64))) 760 761 ins.exports.shr_i64x2(66); // Masked count 762 assertSame(get(mem64, 0, 2), res); 763 764 ins.exports.shr_i64x2(-62); // Masked count 765 assertSame(get(mem64, 0, 2), res); 766 767 // The ion code generator has multiple paths here, for < 32 and >= 32 768 for ( let shift of [27, 45, 63, 64, -1, -231] ) { 769 ins.exports["shr_i64x2_" + shift](); 770 assertSame(get(mem64, 0, 2), as.map(shr(shift & 63, 64))) 771 } 772 773 // Narrow 774 775 var ins = wasmEvalText(` 776 (module 777 (memory (export "mem") 1 1) 778 (func (export "narrow_i16x8_s") 779 (v128.store (i32.const 0) (i8x16.narrow_i16x8_s (v128.load (i32.const 16)) (v128.load (i32.const 32))))) 780 (func (export "narrow_i16x8_u") 781 (v128.store (i32.const 0) (i8x16.narrow_i16x8_u (v128.load (i32.const 16)) (v128.load (i32.const 32))))) 782 (func (export "narrow_i32x4_s") 783 (v128.store (i32.const 0) (i16x8.narrow_i32x4_s (v128.load (i32.const 16)) (v128.load (i32.const 32))))) 784 (func (export "narrow_i32x4_u") 785 (v128.store (i32.const 0) (i16x8.narrow_i32x4_u (v128.load (i32.const 16)) (v128.load (i32.const 32))))))`); 786 787 var mem8 = new Int8Array(ins.exports.mem.buffer); 788 var mem8u = new Uint8Array(ins.exports.mem.buffer); 789 var mem16 = new Int16Array(ins.exports.mem.buffer); 790 var mem16u = new Uint16Array(ins.exports.mem.buffer); 791 var mem32 = new Int32Array(ins.exports.mem.buffer); 792 793 var as = [1, 267, 3987, 14523, 32768, 3, 312, 4876].map((x) => sign_extend(x, 16)); 794 var bs = [2, 312, 4876, 15987, 33777, 1, 267, 3987].map((x) => sign_extend(x, 16)); 795 796 set(mem16, 8, as); 797 set(mem16, 16, bs); 798 799 ins.exports.narrow_i16x8_s(); 800 var cs = as.concat(...bs).map((x) => signed_saturate(x, 8)); 801 assertSame(get(mem8, 0, 16), cs); 802 803 ins.exports.narrow_i16x8_u(); 804 var cs = as.concat(...bs).map((x) => unsigned_saturate(x, 8)); 805 assertSame(get(mem8u, 0, 16), cs); 806 807 var xs = [1, 3987, 14523, 32768].map((x) => x << 16).map((x) => sign_extend(x, 32)); 808 var ys = [2, 4876, 15987, 33777].map((x) => x << 16).map((x) => sign_extend(x, 32)); 809 810 set(mem32, 4, xs); 811 set(mem32, 8, ys); 812 813 ins.exports.narrow_i32x4_s(); 814 var cs = xs.concat(...ys).map((x) => signed_saturate(x, 16)); 815 assertSame(get(mem16, 0, 8), cs); 816 817 ins.exports.narrow_i32x4_u(); 818 var cs = xs.concat(...ys).map((x) => unsigned_saturate(x, 16)); 819 assertSame(get(mem16u, 0, 8), cs); 820 821 // Extend low/high 822 823 var ins = wasmEvalText(` 824 (module 825 (memory (export "mem") 1 1) 826 (func (export "extend_low_i8x16_s") 827 (v128.store (i32.const 0) (i16x8.extend_low_i8x16_s (v128.load (i32.const 16))))) 828 (func (export "extend_high_i8x16_s") 829 (v128.store (i32.const 0) (i16x8.extend_high_i8x16_s (v128.load (i32.const 16))))) 830 (func (export "extend_low_i8x16_u") 831 (v128.store (i32.const 0) (i16x8.extend_low_i8x16_u (v128.load (i32.const 16))))) 832 (func (export "extend_high_i8x16_u") 833 (v128.store (i32.const 0) (i16x8.extend_high_i8x16_u (v128.load (i32.const 16))))) 834 (func (export "extend_low_i16x8_s") 835 (v128.store (i32.const 0) (i32x4.extend_low_i16x8_s (v128.load (i32.const 16))))) 836 (func (export "extend_high_i16x8_s") 837 (v128.store (i32.const 0) (i32x4.extend_high_i16x8_s (v128.load (i32.const 16))))) 838 (func (export "extend_low_i16x8_u") 839 (v128.store (i32.const 0) (i32x4.extend_low_i16x8_u (v128.load (i32.const 16))))) 840 (func (export "extend_high_i16x8_u") 841 (v128.store (i32.const 0) (i32x4.extend_high_i16x8_u (v128.load (i32.const 16))))))`); 842 843 var mem16 = new Int16Array(ins.exports.mem.buffer); 844 var mem16u = new Uint16Array(ins.exports.mem.buffer); 845 var mem8 = new Int8Array(ins.exports.mem.buffer); 846 var as = [0, 1, 192, 3, 205, 5, 6, 133, 8, 9, 129, 11, 201, 13, 14, 255]; 847 848 set(mem8, 16, as); 849 850 ins.exports.extend_low_i8x16_s(); 851 assertSame(get(mem16, 0, 8), iota(8).map((n) => sign_extend(as[n], 8))); 852 853 ins.exports.extend_high_i8x16_s(); 854 assertSame(get(mem16, 0, 8), iota(8).map((n) => sign_extend(as[n+8], 8))); 855 856 ins.exports.extend_low_i8x16_u(); 857 assertSame(get(mem16u, 0, 8), iota(8).map((n) => zero_extend(as[n], 8))); 858 859 ins.exports.extend_high_i8x16_u(); 860 assertSame(get(mem16u, 0, 8), iota(8).map((n) => zero_extend(as[n+8], 8))); 861 862 var mem32 = new Int32Array(ins.exports.mem.buffer); 863 var mem32u = new Uint32Array(ins.exports.mem.buffer); 864 865 var as = [0, 1, 192, 3, 205, 5, 6, 133].map((x) => x << 8); 866 867 set(mem16, 8, as); 868 869 ins.exports.extend_low_i16x8_s(); 870 assertSame(get(mem32, 0, 4), iota(4).map((n) => sign_extend(as[n], 16))); 871 872 ins.exports.extend_high_i16x8_s(); 873 assertSame(get(mem32, 0, 4), iota(4).map((n) => sign_extend(as[n+4], 16))); 874 875 ins.exports.extend_low_i16x8_u(); 876 assertSame(get(mem32u, 0, 4), iota(4).map((n) => zero_extend(as[n], 16))); 877 878 ins.exports.extend_high_i16x8_u(); 879 assertSame(get(mem32u, 0, 4), iota(4).map((n) => zero_extend(as[n+4], 16))); 880 881 882 // Extract lane. Ion constant folds, so test that too. 883 // 884 // operand is v128 in memory (or constant) 885 // lane index is immediate so we're testing something randomish but not zero 886 // result is scalar (returned directly) 887 888 var ins = wasmEvalText(` 889 (module 890 (memory (export "mem") 1 1) 891 (func (export "extract_i8x16_9") (result i32) 892 (i8x16.extract_lane_s 9 (v128.load (i32.const 16)))) 893 (func (export "const_extract_i8x16_9") (result i32) 894 (i8x16.extract_lane_s 9 (v128.const i8x16 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16))) 895 (func (export "extract_u8x16_6") (result i32) 896 (i8x16.extract_lane_u 6 (v128.load (i32.const 16)))) 897 (func (export "const_extract_u8x16_9") (result i32) 898 (i8x16.extract_lane_u 9 (v128.const i8x16 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16))) 899 (func (export "extract_i16x8_5") (result i32) 900 (i16x8.extract_lane_s 5 (v128.load (i32.const 16)))) 901 (func (export "const_extract_i16x8_5") (result i32) 902 (i16x8.extract_lane_s 5 (v128.const i16x8 -1 -2 -3 -4 -5 -6 -7 -8))) 903 (func (export "extract_u16x8_3") (result i32) 904 (i16x8.extract_lane_u 3 (v128.load (i32.const 16)))) 905 (func (export "const_extract_u16x8_3") (result i32) 906 (i16x8.extract_lane_u 3 (v128.const i16x8 -1 -2 -3 -4 -5 -6 -7 -8))) 907 (func (export "extract_i32x4_2") (result i32) 908 (i32x4.extract_lane 2 (v128.load (i32.const 16)))) 909 (func (export "const_extract_i32x4_2") (result i32) 910 (i32x4.extract_lane 2 (v128.const i32x4 -1 -2 -3 -4))) 911 (func (export "extract_i64x2_1") (result i64) 912 (i64x2.extract_lane 1 (v128.load (i32.const 16)))) 913 (func (export "const_extract_i64x2_1") (result i64) 914 (i64x2.extract_lane 1 (v128.const i64x2 -1 -2))) 915 (func (export "extract_f32x4_2") (result f32) 916 (f32x4.extract_lane 2 (v128.load (i32.const 16)))) 917 (func (export "const_extract_f32x4_2") (result f32) 918 (f32x4.extract_lane 2 (v128.const f32x4 -1 -2 -3 -4))) 919 (func (export "extract_f64x2_1") (result f64) 920 (f64x2.extract_lane 1 (v128.load (i32.const 16)))) 921 (func (export "const_extract_f64x2_1") (result f64) 922 (f64x2.extract_lane 1 (v128.const f64x2 -1 -2))))`); 923 924 var mem8 = new Uint8Array(ins.exports.mem.buffer); 925 var as = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 926 var bs = as.map((x) => -x); 927 928 set(mem8, 16, as) 929 assertEq(ins.exports.extract_i8x16_9(), as[9]); 930 931 set(mem8, 16, bs) 932 assertEq(ins.exports.extract_u8x16_6(), 256 - as[6]); 933 934 assertEq(ins.exports.const_extract_i8x16_9(), -10); 935 assertEq(ins.exports.const_extract_u8x16_9(), 256-10); 936 937 var mem16 = new Uint16Array(ins.exports.mem.buffer); 938 var as = [1, 2, 3, 4, 5, 6, 7, 8]; 939 var bs = as.map((x) => -x); 940 941 set(mem16, 8, as) 942 assertEq(ins.exports.extract_i16x8_5(), as[5]); 943 944 set(mem16, 8, bs) 945 assertEq(ins.exports.extract_u16x8_3(), 65536 - as[3]); 946 947 assertEq(ins.exports.const_extract_i16x8_5(), -6); 948 assertEq(ins.exports.const_extract_u16x8_3(), 65536-4); 949 950 var mem32 = new Uint32Array(ins.exports.mem.buffer); 951 var as = [1, 2, 3, 4]; 952 953 set(mem32, 4, as) 954 assertEq(ins.exports.extract_i32x4_2(), as[2]); 955 956 assertEq(ins.exports.const_extract_i32x4_2(), -3); 957 958 var mem32 = new Float32Array(ins.exports.mem.buffer); 959 var as = [1.5, 2.5, 3.5, 4.5]; 960 961 set(mem32, 4, as) 962 assertEq(ins.exports.extract_f32x4_2(), as[2]); 963 964 assertEq(ins.exports.const_extract_f32x4_2(), -3); 965 966 var mem64 = new Float64Array(ins.exports.mem.buffer); 967 var as = [1.5, 2.5]; 968 969 set(mem64, 2, as) 970 assertEq(ins.exports.extract_f64x2_1(), as[1]); 971 972 assertEq(ins.exports.const_extract_f64x2_1(), -2); 973 974 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 975 var as = [12345, 67890]; 976 977 set(mem64, 2, as) 978 assertSame(ins.exports.extract_i64x2_1(), as[1]); 979 980 assertEq(ins.exports.const_extract_i64x2_1(), -2n); 981 982 // Replace lane 983 // 984 // operand 1 is v128 in memory 985 // operand 2 is immediate scalar 986 // lane index is immediate so we're testing something randomish but not zero 987 // (note though that fp operations have special cases for zero) 988 // result is v128 in memory 989 990 var ins = wasmEvalText(` 991 (module 992 (memory (export "mem") 1 1) 993 (func (export "replace_i8x16_9") (param $value i32) 994 (v128.store (i32.const 0) 995 (i8x16.replace_lane 9 (v128.load (i32.const 16)) (local.get $value)))) 996 (func (export "replace_i16x8_5") (param $value i32) 997 (v128.store (i32.const 0) 998 (i16x8.replace_lane 5 (v128.load (i32.const 16)) (local.get $value)))) 999 (func (export "replace_i32x4_3") (param $value i32) 1000 (v128.store (i32.const 0) 1001 (i32x4.replace_lane 3 (v128.load (i32.const 16)) (local.get $value)))) 1002 (func (export "replace_i64x2_1") (param $value i64) 1003 (v128.store (i32.const 0) 1004 (i64x2.replace_lane 1 (v128.load (i32.const 16)) (local.get $value)))) 1005 (func (export "replace_f32x4_0") (param $value f32) 1006 (v128.store (i32.const 0) 1007 (f32x4.replace_lane 0 (v128.load (i32.const 16)) (local.get $value)))) 1008 (func (export "replace_f32x4_3") (param $value f32) 1009 (v128.store (i32.const 0) 1010 (f32x4.replace_lane 3 (v128.load (i32.const 16)) (local.get $value)))) 1011 (func (export "replace_f64x2_0") (param $value f64) 1012 (v128.store (i32.const 0) 1013 (f64x2.replace_lane 0 (v128.load (i32.const 16)) (local.get $value)))) 1014 (func (export "replace_f64x2_1") (param $value f64) 1015 (v128.store (i32.const 0) 1016 (f64x2.replace_lane 1 (v128.load (i32.const 16)) (local.get $value)))))`); 1017 1018 1019 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1020 var as = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 1021 1022 set(mem8, 16, as) 1023 ins.exports.replace_i8x16_9(42); 1024 assertSame(get(mem8, 0, 16), upd(as, 9, 42)); 1025 1026 var mem16 = new Uint16Array(ins.exports.mem.buffer); 1027 var as = [1, 2, 3, 4, 5, 6, 7, 8]; 1028 1029 set(mem16, 8, as) 1030 ins.exports.replace_i16x8_5(42); 1031 assertSame(get(mem16, 0, 8), upd(as, 5, 42)); 1032 1033 var mem32 = new Uint32Array(ins.exports.mem.buffer); 1034 var as = [1, 2, 3, 4]; 1035 1036 set(mem32, 4, as) 1037 ins.exports.replace_i32x4_3(42); 1038 assertSame(get(mem32, 0, 4), upd(as, 3, 42)); 1039 1040 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 1041 var as = [1, 2]; 1042 1043 set(mem64, 2, as) 1044 ins.exports.replace_i64x2_1(42n); 1045 assertSame(get(mem64, 0, 2), upd(as, 1, 42)); 1046 1047 var mem32 = new Float32Array(ins.exports.mem.buffer); 1048 var as = [1.5, 2.5, 3.5, 4.5]; 1049 1050 set(mem32, 4, as) 1051 ins.exports.replace_f32x4_0(42.5); 1052 assertSame(get(mem32, 0, 4), upd(as, 0, 42.5)); 1053 1054 set(mem32, 4, as) 1055 ins.exports.replace_f32x4_3(42.5); 1056 assertSame(get(mem32, 0, 4), upd(as, 3, 42.5)); 1057 1058 var mem64 = new Float64Array(ins.exports.mem.buffer); 1059 var as = [1.5, 2.5]; 1060 1061 set(mem64, 2, as) 1062 ins.exports.replace_f64x2_0(42.5); 1063 assertSame(get(mem64, 0, 2), upd(as, 0, 42.5)); 1064 1065 set(mem64, 2, as) 1066 ins.exports.replace_f64x2_1(42.5); 1067 assertSame(get(mem64, 0, 2), upd(as, 1, 42.5)); 1068 1069 // Load and splat 1070 // 1071 // Operand is memory address of scalar 1072 // Result is v128 in memory 1073 1074 var ins = wasmEvalText(` 1075 (module 1076 (memory (export "mem") 1 1) 1077 (func (export "load_splat_v8x16") (param $addr i32) 1078 (v128.store (i32.const 0) (v128.load8_splat (local.get $addr)))) 1079 (func (export "load_splat_v16x8") (param $addr i32) 1080 (v128.store (i32.const 0) (v128.load16_splat (local.get $addr)))) 1081 (func (export "load_splat_v32x4") (param $addr i32) 1082 (v128.store (i32.const 0) (v128.load32_splat (local.get $addr)))) 1083 (func (export "load_splat_v64x2") (param $addr i32) 1084 (v128.store (i32.const 0) (v128.load64_splat (local.get $addr)))))`); 1085 1086 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1087 mem8[37] = 42; 1088 ins.exports.load_splat_v8x16(37); 1089 assertSame(get(mem8, 0, 16), [42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42]); 1090 1091 var mem16 = new Uint16Array(ins.exports.mem.buffer); 1092 mem16[37] = 69; 1093 ins.exports.load_splat_v16x8(37*2); 1094 assertSame(get(mem16, 0, 8), [69, 69, 69, 69, 69, 69, 69, 69]); 1095 1096 var mem32 = new Int32Array(ins.exports.mem.buffer); 1097 mem32[37] = 83; 1098 ins.exports.load_splat_v32x4(37*4); 1099 assertSame(get(mem32, 0, 4), [83, 83, 83, 83]); 1100 1101 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 1102 mem64[37] = 83n; 1103 ins.exports.load_splat_v64x2(37*8); 1104 assertSame(get(mem64, 0, 2), [83, 83]); 1105 1106 // Load and zero 1107 // 1108 // Operand is memory address of scalar 1109 // Result is v128 in memory 1110 1111 var ins = wasmEvalText(` 1112 (module 1113 (memory (export "mem") 1 1) 1114 (func (export "load32_zero") (param $addr i32) 1115 (v128.store (i32.const 0) (v128.load32_zero (local.get $addr)))) 1116 (func (export "load64_zero") (param $addr i32) 1117 (v128.store (i32.const 0) (v128.load64_zero (local.get $addr)))))`); 1118 1119 var mem32 = new Int32Array(ins.exports.mem.buffer); 1120 mem32[37] = 0x12345678; 1121 mem32[38] = 0xffffffff; 1122 mem32[39] = 0xfffffffe; 1123 mem32[40] = 0xfffffffd; 1124 ins.exports.load32_zero(37*4); 1125 assertSame(get(mem32, 0, 4), [0x12345678, 0, 0, 0]); 1126 1127 var mem64 = new BigInt64Array(ins.exports.mem.buffer); 1128 mem64[37] = 0x12345678abcdef01n; 1129 mem64[38] = 0xffffffffffffffffn; 1130 ins.exports.load64_zero(37*8); 1131 assertSame(get(mem64, 0, 2), [0x12345678abcdef01n, 0n]); 1132 1133 // Load and extend 1134 // 1135 // Operand is memory address of 64-bit scalar representing 8, 4, or 2 values 1136 // Result is v128 in memory 1137 1138 var ins = wasmEvalText(` 1139 (module 1140 (memory (export "mem") 1 1) 1141 (func (export "load8x8_s") (param $addr i32) 1142 (v128.store (i32.const 0) (v128.load8x8_s (local.get $addr)))) 1143 (func (export "load8x8_u") (param $addr i32) 1144 (v128.store (i32.const 0) (v128.load8x8_u (local.get $addr)))) 1145 (func (export "load16x4_s") (param $addr i32) 1146 (v128.store (i32.const 0) (v128.load16x4_s (local.get $addr)))) 1147 (func (export "load16x4_u") (param $addr i32) 1148 (v128.store (i32.const 0) (v128.load16x4_u (local.get $addr)))) 1149 (func (export "load32x2_s") (param $addr i32) 1150 (v128.store (i32.const 0) (v128.load32x2_s (local.get $addr)))) 1151 (func (export "load32x2_u") (param $addr i32) 1152 (v128.store (i32.const 0) (v128.load32x2_u (local.get $addr)))))`); 1153 1154 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1155 var mem16s = new Int16Array(ins.exports.mem.buffer); 1156 var mem16u = new Uint16Array(ins.exports.mem.buffer); 1157 var mem32s = new Int32Array(ins.exports.mem.buffer); 1158 var mem32u = new Uint32Array(ins.exports.mem.buffer); 1159 var mem64s = new BigInt64Array(ins.exports.mem.buffer); 1160 var mem64u = new BigUint64Array(ins.exports.mem.buffer); 1161 var xs = [42, 129, 2, 212, 44, 27, 12, 199]; 1162 set(mem8, 48, xs); 1163 1164 ins.exports.load8x8_s(48); 1165 assertSame(get(mem16s, 0, 8), xs.map((x) => sign_extend(x, 8))); 1166 1167 ins.exports.load8x8_u(48); 1168 assertSame(get(mem16u, 0, 8), xs.map((x) => zero_extend(x, 8))); 1169 1170 var xs = [(42 << 8) | 129, (212 << 8) | 2, (44 << 8) | 27, (199 << 8) | 12]; 1171 set(mem16u, 24, xs); 1172 1173 ins.exports.load16x4_s(48); 1174 assertSame(get(mem32s, 0, 4), xs.map((x) => sign_extend(x, 16))); 1175 1176 ins.exports.load16x4_u(48); 1177 assertSame(get(mem32u, 0, 4), xs.map((x) => zero_extend(x, 16))); 1178 1179 var xs = [5, -8]; 1180 set(mem32u, 12, xs); 1181 1182 ins.exports.load32x2_s(48); 1183 assertSame(get(mem64s, 0, 2), xs.map((x) => sign_extend(x, 32))); 1184 1185 ins.exports.load32x2_u(48); 1186 assertSame(get(mem64s, 0, 2), xs.map((x) => zero_extend(x, 32))); 1187 1188 // Vector select 1189 // 1190 // Operands and results are all in memory 1191 1192 var ins = wasmEvalText(` 1193 (module 1194 (memory (export "mem") 1 1) 1195 (func (export "bitselect_v128") 1196 (v128.store (i32.const 0) 1197 (v128.bitselect (v128.load (i32.const 16)) 1198 (v128.load (i32.const 32)) 1199 (v128.load (i32.const 48))))))`); 1200 1201 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1202 set(mem8, 16, iota(16).map((_) => 0xAA)); 1203 set(mem8, 32, iota(16).map((_) => 0x55)); 1204 1205 set(mem8, 48, iota(16).map((_) => 0x99)); 1206 ins.exports.bitselect_v128(); 1207 assertSame(get(mem8, 0, 16), iota(16).map((_) => 0xCC)); 1208 1209 set(mem8, 48, iota(16).map((_) => 0x77)); 1210 ins.exports.bitselect_v128(); 1211 assertSame(get(mem8, 0, 16), iota(16).map((_) => 0x22)); 1212 1213 // Vector shuffle 1214 // 1215 // Operands and results are all in memory 1216 1217 var ins = wasmEvalText(` 1218 (module 1219 (memory (export "mem") 1 1) 1220 ;; the result interleaves the low eight bytes of the inputs 1221 (func (export "shuffle1") 1222 (v128.store (i32.const 0) 1223 (i8x16.shuffle 0 16 1 17 2 18 3 19 4 20 5 21 6 22 7 23 1224 (v128.load (i32.const 16)) 1225 (v128.load (i32.const 32))))) 1226 ;; ditto the high eight bytes 1227 (func (export "shuffle2") 1228 (v128.store (i32.const 0) 1229 (i8x16.shuffle 8 24 9 25 10 26 11 27 12 28 13 29 14 30 15 31 1230 (v128.load (i32.const 16)) 1231 (v128.load (i32.const 32))))))`); 1232 1233 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1234 var xs = iota(16).map((n) => 0xA0 + n); 1235 var ys = iota(16).map((n) => 0x50 + n); 1236 set(mem8, 16, xs); 1237 set(mem8, 32, ys); 1238 1239 ins.exports.shuffle1(); 1240 assertSame(get(mem8, 0, 16), iota(16).map((x) => ((x & 1) ? ys : xs)[x >>> 1])) 1241 1242 ins.exports.shuffle2(); 1243 assertSame(get(mem8, 0, 16), iota(32).map((x) => ((x & 1) ? ys : xs)[x >>> 1]).slice(16)); 1244 1245 // Vector swizzle (variable permute). 1246 // 1247 // Case 1: Operands and results are all in memory 1248 1249 var ins = wasmEvalText(` 1250 (module 1251 (memory (export "mem") 1 1) 1252 (func (export "swizzle") 1253 (v128.store (i32.const 0) 1254 (i8x16.swizzle (v128.load (i32.const 16)) (v128.load (i32.const 32))))))`); 1255 1256 var mem8 = new Uint8Array(ins.exports.mem.buffer); 1257 1258 var xs = [100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115]; 1259 set(mem8, 16, xs); 1260 1261 set(mem8, 32, [1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14]); 1262 ins.exports.swizzle(); 1263 assertSame(get(mem8, 0, 16), [101,100,103,102,105,104,107,106,109,108,111,110,113,112,115,114]); 1264 1265 set(mem8, 32, [9,8,11,10,13,12,16,14,1,0,3,2,5,192,7,6]); 1266 ins.exports.swizzle(); 1267 assertSame(get(mem8, 0, 16), [109,108,111,110,113,112,0,114,101,100,103,102,105,0,107,106]); 1268 1269 // Case 2: The mask operand is a constant; the swizzle gets optimized into a 1270 // shuffle (also see ion-analysis.js). 1271 1272 for ( let [mask, expected] of [[[1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14], 1273 [101,100,103,102,105,104,107,106,109,108,111,110,113,112,115,114]], 1274 [[9,8,11,10,13,12,16,14,1,0,3,2,5,192,7,6], 1275 [109,108,111,110,113,112,0,114,101,100,103,102,105,0,107,106]]] ) { 1276 1277 let ins = wasmEvalText(` 1278 (module 1279 (memory (export "mem") 1 1) 1280 (func (export "swizzle") 1281 (v128.store (i32.const 0) 1282 (i8x16.swizzle (v128.load (i32.const 16)) (v128.const i8x16 ${mask.join(' ')}))))) 1283 `); 1284 1285 let mem8 = new Uint8Array(ins.exports.mem.buffer); 1286 set(mem8, 16, [100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115]); 1287 ins.exports.swizzle(); 1288 assertSame(get(mem8, 0, 16), expected); 1289 } 1290 1291 // Convert integer to floating point 1292 1293 var ins = wasmEvalText(` 1294 (module 1295 (memory (export "mem") 1 1) 1296 (func (export "convert_s") 1297 (v128.store (i32.const 0) 1298 (f32x4.convert_i32x4_s (v128.load (i32.const 16))))) 1299 (func (export "convert_u") 1300 (v128.store (i32.const 0) 1301 (f32x4.convert_i32x4_u (v128.load (i32.const 16))))))`); 1302 1303 var mem32s = new Int32Array(ins.exports.mem.buffer); 1304 var mem32f = new Float32Array(ins.exports.mem.buffer); 1305 var xs = [1, -9, 77987, -34512]; 1306 1307 set(mem32s, 4, xs); 1308 ins.exports.convert_s(); 1309 assertSame(get(mem32f, 0, 4), xs); 1310 1311 var mem32u = new Uint32Array(ins.exports.mem.buffer); 1312 var ys = xs.map((x) => x>>>0); 1313 1314 set(mem32u, 4, ys); 1315 ins.exports.convert_u(); 1316 assertSame(get(mem32f, 0, 4), ys.map(Math.fround)); 1317 1318 // Convert floating point to integer with saturating truncation 1319 1320 var ins = wasmEvalText(` 1321 (module 1322 (memory (export "mem") 1 1) 1323 (func (export "trunc_sat_s") 1324 (v128.store (i32.const 0) 1325 (i32x4.trunc_sat_f32x4_s (v128.load (i32.const 16))))) 1326 (func (export "trunc_sat_u") 1327 (v128.store (i32.const 0) 1328 (i32x4.trunc_sat_f32x4_u (v128.load (i32.const 16))))))`); 1329 1330 var mem32s = new Int32Array(ins.exports.mem.buffer); 1331 var mem32u = new Uint32Array(ins.exports.mem.buffer); 1332 var mem32f = new Float32Array(ins.exports.mem.buffer); 1333 var xs = [1.5, -9.5, 7.5e12, -8e13]; 1334 1335 set(mem32f, 4, xs); 1336 ins.exports.trunc_sat_s(); 1337 assertSame(get(mem32s, 0, 4), [1, -9, 0x7FFFFFFF, -0x80000000]); 1338 1339 var xs = [1.5, -9.5, 7.5e12, 812]; 1340 set(mem32f, 4, xs); 1341 ins.exports.trunc_sat_u(); 1342 assertSame(get(mem32u, 0, 4), [1, 0, 0xFFFFFFFF, 812]); 1343 1344 var xs = [0, -0, 0x80860000, 0x100000000]; 1345 set(mem32f, 4, xs); 1346 ins.exports.trunc_sat_u(); 1347 assertSame(get(mem32u, 0, 4), [0, 0, 0x80860000, 0xFFFFFFFF]); 1348 1349 // Loops and blocks. This should at least test "sync" in the baseline compiler. 1350 1351 var ins = wasmEvalText(` 1352 (module 1353 (memory (export "mem") 1 1) 1354 (func $f (param $count i32) (param $v v128) (result v128) 1355 (local $tmp v128) 1356 (block $B1 1357 (loop $L1 1358 (br_if $B1 (i32.eqz (local.get $count))) 1359 (local.set $tmp (i32x4.add (local.get $tmp) (local.get $v))) 1360 (local.set $count (i32.sub (local.get $count) (i32.const 1))) 1361 (br $L1))) 1362 (local.get $tmp)) 1363 (func (export "run") (param $count i32) 1364 (v128.store (i32.const 0) 1365 (call $f (local.get $count) (v128.load (i32.const 16))))))`); 1366 1367 var mem32 = new Int32Array(ins.exports.mem.buffer); 1368 set(mem32, 4, [1,2,3,4]); 1369 ins.exports.run(7); 1370 assertSame(get(mem32, 0, 4), [7,14,21,28]); 1371 1372 // Lots of parameters, this should trigger stack parameter passing 1373 // 1374 // 10 parameters in memory, we load them and pass them and operate on them. 1375 1376 var ins = wasmEvalText(` 1377 (module 1378 (memory (export "mem") 1 1) 1379 (func $f (param $v0 v128) (param $v1 v128) (param $v2 v128) (param $v3 v128) (param $v4 v128) 1380 (param $v5 v128) (param $v6 v128) (param $v7 v128) (param $v8 v128) (param $v9 v128) 1381 (result v128) 1382 (i32x4.add (local.get $v0) 1383 (i32x4.add (local.get $v1) 1384 (i32x4.add (local.get $v2) 1385 (i32x4.add (local.get $v3) 1386 (i32x4.add (local.get $v4) 1387 (i32x4.add (local.get $v5) 1388 (i32x4.add (local.get $v6) 1389 (i32x4.add (local.get $v7) 1390 (i32x4.add (local.get $v8) (local.get $v9))))))))))) 1391 (func (export "run") 1392 (v128.store (i32.const 0) 1393 (call $f (v128.load (i32.const ${16*1})) 1394 (v128.load (i32.const ${16*2})) 1395 (v128.load (i32.const ${16*3})) 1396 (v128.load (i32.const ${16*4})) 1397 (v128.load (i32.const ${16*5})) 1398 (v128.load (i32.const ${16*6})) 1399 (v128.load (i32.const ${16*7})) 1400 (v128.load (i32.const ${16*8})) 1401 (v128.load (i32.const ${16*9})) 1402 (v128.load (i32.const ${16*10}))))))`); 1403 1404 1405 var mem32 = new Int32Array(ins.exports.mem.buffer); 1406 var sum = [0, 0, 0, 0]; 1407 for ( let i=1; i <= 10; i++ ) { 1408 let v = [1,2,3,4].map((x) => x*i); 1409 set(mem32, 4*i, v); 1410 for ( let j=0; j < 4; j++ ) 1411 sum[j] += v[j]; 1412 } 1413 1414 ins.exports.run(); 1415 1416 assertSame(get(mem32, 0, 4), sum); 1417 1418 // Globals. 1419 // 1420 // We have a number of different code paths and representations and 1421 // need to test them all. 1422 // 1423 // Cases: 1424 // - private global, mutable / immutable, initialized from constant or imported immutable global 1425 // - exported global, mutable / immutable, initialized from constant or imported immutable global 1426 // - imported global, mutable / immutable 1427 // - imported global that's re-exported, mutable / immutable 1428 1429 // Global used for initialization below. 1430 1431 var init = (function () { 1432 var ins = wasmEvalText(` 1433 (module 1434 (global (export "init") v128 (v128.const i32x4 9 8 7 6)))`); 1435 return ins.exports; 1436 })(); 1437 1438 for ( let exportspec of ['', '(export "g")'] ) { 1439 1440 // Private/exported immutable initialized from constant 1441 1442 let ins1 = wasmEvalText(` 1443 (module 1444 (memory (export "mem") 1 1) 1445 (global $g ${exportspec} v128 (v128.const i32x4 9 8 7 6)) 1446 (func (export "get") (param $dest i32) 1447 (v128.store (local.get $dest) (global.get $g))))`); 1448 1449 let mem1 = new Int32Array(ins1.exports.mem.buffer); 1450 ins1.exports.get(0); 1451 assertSame(get(mem1, 0, 4), [9, 8, 7, 6]); 1452 1453 // Private/exported mutable initialized from constant 1454 1455 let ins2 = wasmEvalText(` 1456 (module 1457 (memory (export "mem") 1 1) 1458 (global $g ${exportspec} (mut v128) (v128.const i32x4 9 8 7 6)) 1459 (func (export "put") (param $val i32) 1460 (global.set $g (i32x4.splat (local.get $val)))) 1461 (func (export "get") (param $dest i32) 1462 (v128.store (local.get $dest) (global.get $g))))`); 1463 1464 let mem2 = new Int32Array(ins2.exports.mem.buffer); 1465 ins2.exports.get(0); 1466 assertSame(get(mem2, 0, 4), [9, 8, 7, 6]); 1467 ins2.exports.put(37); 1468 ins2.exports.get(0); 1469 assertSame(get(mem2, 0, 4), [37, 37, 37, 37]); 1470 1471 // Private/exported immutable initialized from imported immutable global 1472 1473 let ins3 = wasmEvalText(` 1474 (module 1475 (global $init (import "m" "init") v128) 1476 (memory (export "mem") 1 1) 1477 (global $g ${exportspec} v128 (global.get $init)) 1478 (func (export "get") (param $dest i32) 1479 (v128.store (local.get $dest) (global.get $g))))`, 1480 {m:init}); 1481 1482 let mem3 = new Int32Array(ins3.exports.mem.buffer); 1483 ins3.exports.get(0); 1484 assertSame(get(mem3, 0, 4), [9, 8, 7, 6]); 1485 1486 // Private/exported mutable initialized from imported immutable global 1487 1488 let ins4 = wasmEvalText(` 1489 (module 1490 (global $init (import "m" "init") v128) 1491 (memory (export "mem") 1 1) 1492 (global $g ${exportspec} (mut v128) (global.get $init)) 1493 (func (export "put") (param $val i32) 1494 (global.set $g (i32x4.splat (local.get $val)))) 1495 (func (export "get") (param $dest i32) 1496 (v128.store (local.get $dest) (global.get $g))))`, 1497 {m:init}); 1498 1499 let mem4 = new Int32Array(ins4.exports.mem.buffer); 1500 ins4.exports.get(0); 1501 assertSame(get(mem4, 0, 4), [9, 8, 7, 6]); 1502 ins4.exports.put(37); 1503 ins4.exports.get(0); 1504 assertSame(get(mem4, 0, 4), [37, 37, 37, 37]); 1505 1506 // Imported private/re-exported immutable 1507 1508 let ins5 = wasmEvalText(` 1509 (module 1510 (global $g ${exportspec} (import "m" "init") v128) 1511 (memory (export "mem") 1 1) 1512 (func (export "get") (param $dest i32) 1513 (v128.store (local.get $dest) (global.get $g))))`, 1514 {m:init}); 1515 1516 let mem5 = new Int32Array(ins5.exports.mem.buffer); 1517 ins5.exports.get(0); 1518 assertSame(get(mem5, 0, 4), [9, 8, 7, 6]); 1519 1520 // Imported private/re-exported mutable 1521 1522 let mutg = (function () { 1523 var ins = wasmEvalText(` 1524 (module 1525 (global (export "mutg") (mut v128) (v128.const i32x4 19 18 17 16)))`); 1526 return ins.exports; 1527 })(); 1528 1529 let ins6 = wasmEvalText(` 1530 (module 1531 (global $g ${exportspec} (import "m" "mutg") (mut v128)) 1532 (memory (export "mem") 1 1) 1533 (func (export "put") (param $val i32) 1534 (global.set $g (i32x4.splat (local.get $val)))) 1535 (func (export "get") (param $dest i32) 1536 (v128.store (local.get $dest) (global.get $g))))`, 1537 {m:mutg}); 1538 1539 let mem6 = new Int32Array(ins6.exports.mem.buffer); 1540 ins6.exports.get(0); 1541 assertSame(get(mem6, 0, 4), [19, 18, 17, 16]); 1542 ins6.exports.put(37); 1543 ins6.exports.get(0); 1544 assertSame(get(mem6, 0, 4), [37, 37, 37, 37]); 1545 } 1546 1547 // Imports and exports that pass and return v128 1548 1549 var insworker = wasmEvalText(` 1550 (module 1551 (func (export "worker") (param v128) (result v128) 1552 (i8x16.add (local.get 0) (v128.const i8x16 ${iota(16).join(' ')}))))`); 1553 1554 var insrun = wasmEvalText(` 1555 (module 1556 (import "" "worker" (func $worker (param v128) (result v128))) 1557 (memory (export "mem") 1 1) 1558 (func (export "run") (param $srcloc i32) (param $destloc i32) 1559 (v128.store (local.get $destloc) 1560 (call $worker (v128.load (local.get $srcloc))))))`, 1561 {"":insworker.exports}); 1562 1563 var mem = new Uint8Array(insrun.exports.mem.buffer); 1564 var xs = iota(16).map((x) => x+5); 1565 set(mem, 0, xs); 1566 insrun.exports.run(0, 16); 1567 assertSame(get(mem, 16, 16), xs.map((x,i) => x+i)) 1568 1569 // Make sure JS<->wasm call guards are sensible. 1570 1571 // Calling from JS to export that accepts v128. 1572 assertErrorMessage(() => insworker.exports.worker(), 1573 TypeError, 1574 /cannot pass.*value.*to or from JS/); 1575 1576 // Calling from wasm with v128 to import that comes from JS. The instantiation 1577 // will succeed even if the param type of the import is v128 (see "create a host 1578 // function" in the Wasm JSAPI spec), it is the act of invoking it that checks 1579 // that verboten types are not used (see "run a host function", ibid.). 1580 var badImporter = wasmEvalText(` 1581 (module 1582 (import "" "worker" (func $worker (param v128) (result v128))) 1583 (func (export "run") 1584 (drop (call $worker (v128.const i32x4 0 1 2 3)))))`, 1585 {"":{worker: function(a) { return a; }}}); 1586 1587 assertErrorMessage(() => badImporter.exports.run(), 1588 TypeError, 1589 /cannot pass.*value.*to or from JS/); 1590 1591 // Imports and exports that pass and return v128 as stack (not register) args. 1592 1593 var exportWithStackArgs = wasmEvalText(` 1594 (module 1595 (func (export "worker") (param v128) (param v128) (param v128) (param v128) 1596 (param v128) (param v128) (param v128) (param v128) 1597 (param v128) (param v128) (param v128) (param v128) 1598 (param v128) (param v128) 1599 (result v128 v128) 1600 (i8x16.add (local.get 3) (local.get 12)) 1601 (local.get 7)))`); 1602 1603 var importWithStackArgs = wasmEvalText(` 1604 (module 1605 (type $t1 (func (param v128) (param v128) (param v128) (param v128) 1606 (param v128) (param v128) (param v128) (param v128) 1607 (param v128) (param v128) (param v128) (param v128) 1608 (param v128) (param v128) 1609 (result v128 v128))) 1610 (import "" "worker" (func $worker (type $t1))) 1611 (memory (export "mem") 1 1) 1612 (table funcref (elem $worker)) 1613 (func (export "run") 1614 (i32.const 16) 1615 (call_indirect (type $t1) (v128.const i32x4 1 1 1 1) (v128.const i32x4 2 2 2 2) (v128.const i32x4 3 3 3 3) 1616 (v128.const i32x4 4 4 4 4) (v128.const i32x4 5 5 5 5) (v128.const i32x4 6 6 6 6) 1617 (v128.const i32x4 7 7 7 7) (v128.const i32x4 8 8 8 8) (v128.const i32x4 9 9 9 9) 1618 (v128.const i32x4 10 10 10 10) (v128.const i32x4 11 11 11 11) (v128.const i32x4 12 12 12 12) 1619 (v128.const i32x4 13 13 13 13) (v128.const i32x4 14 14 14 14) 1620 (i32.const 0)) 1621 drop 1622 v128.store 1623 (i32.const 0) 1624 (call $worker (v128.const i32x4 1 1 1 1) (v128.const i32x4 2 2 2 2) (v128.const i32x4 3 3 3 3) 1625 (v128.const i32x4 4 4 4 4) (v128.const i32x4 5 5 5 5) (v128.const i32x4 6 6 6 6) 1626 (v128.const i32x4 7 7 7 7) (v128.const i32x4 8 8 8 8) (v128.const i32x4 9 9 9 9) 1627 (v128.const i32x4 10 10 10 10) (v128.const i32x4 11 11 11 11) (v128.const i32x4 12 12 12 12) 1628 (v128.const i32x4 13 13 13 13) (v128.const i32x4 14 14 14 14)) 1629 drop 1630 v128.store))`, 1631 {"": exportWithStackArgs.exports}); 1632 1633 var mem = new Int32Array(importWithStackArgs.exports.mem.buffer); 1634 importWithStackArgs.exports.run(); 1635 assertSame(get(mem, 0, 4), [17, 17, 17, 17]); 1636 assertSame(get(mem, 4, 4), [17, 17, 17, 17]); 1637 1638 // Imports and exports of v128 globals 1639 1640 var insexporter = wasmEvalText(` 1641 (module 1642 (global (export "myglobal") (mut v128) (v128.const i8x16 ${iota(16).join(' ')})))`); 1643 1644 var insimporter = wasmEvalText(` 1645 (module 1646 (import "m" "myglobal" (global $g (mut v128))) 1647 (memory (export "mem") 1 1) 1648 (func (export "run") (param $dest i32) 1649 (v128.store (local.get $dest) (global.get $g))))`, 1650 {m:insexporter.exports}); 1651 1652 var mem = new Uint8Array(insimporter.exports.mem.buffer); 1653 insimporter.exports.run(16); 1654 assertSame(get(mem, 16, 16), iota(16)); 1655 1656 // Guards on accessing v128 globals from JS 1657 1658 assertErrorMessage(() => insexporter.exports.myglobal.value = 0, 1659 TypeError, 1660 /cannot pass.*value.*to or from JS/); 1661 1662 assertErrorMessage(function () { let v = insexporter.exports.myglobal.value }, 1663 TypeError, 1664 /cannot pass.*value.*to or from JS/); 1665 1666 // Multi-value cases + v128 parameters to if, block, loop 1667 1668 var ins = wasmEvalText(` 1669 (module 1670 (memory (export "mem") 1 1) 1671 (func $mvreturn (result v128 v128 v128) 1672 (v128.load (i32.const 16)) 1673 (v128.load (i32.const 0)) 1674 (v128.load (i32.const 32))) 1675 (func (export "runreturn") 1676 i32.const 48 1677 (call $mvreturn) 1678 i32x4.sub ;; [-20, -20, -20, -20] 1679 i32x4.sub ;; [31, 32, 33, 34] 1680 v128.store) 1681 (func (export "runif") (param $cond i32) 1682 i32.const 48 1683 (v128.load (i32.const 0)) 1684 (v128.load (i32.const 16)) 1685 (if (param v128) (param v128) (result v128 v128) 1686 (local.get $cond) 1687 (then i32x4.add 1688 (v128.load (i32.const 32))) 1689 (else i32x4.sub 1690 (v128.load (i32.const 0)))) 1691 i32x4.add 1692 v128.store) 1693 (func (export "runblock") 1694 i32.const 48 1695 (v128.load (i32.const 0)) 1696 (v128.load (i32.const 16)) 1697 (block (param v128 v128) (result v128 v128) 1698 i32x4.add 1699 (v128.load (i32.const 32))) 1700 i32x4.add 1701 v128.store) 1702 (func (export "runloop") (param $count i32) 1703 i32.const 48 1704 (v128.load (i32.const 0)) 1705 (v128.load (i32.const 16)) 1706 (block $B (param v128 v128) (result v128 v128) 1707 (loop $L (param v128 v128) (result v128 v128) 1708 i32x4.add 1709 (v128.load (i32.const 32)) 1710 (local.set $count (i32.sub (local.get $count) (i32.const 1))) 1711 (br_if $B (i32.eqz (local.get $count))) 1712 (br $L))) 1713 i32x4.add 1714 v128.store))`); 1715 1716 var mem = new Int32Array(ins.exports.mem.buffer); 1717 set(mem, 0, [1, 2, 3, 4]); 1718 set(mem, 4, [11, 12, 13, 14]); 1719 set(mem, 8, [21, 22, 23, 24]); 1720 1721 // Multi-value returns 1722 1723 ins.exports.runreturn(); 1724 assertSame(get(mem, 12, 4), [31, 32, 33, 34]); 1725 1726 // Multi-parameters to and multi-returns from "if" 1727 1728 // This should be vector@0 + vector@16 + vector@32 1729 ins.exports.runif(1); 1730 assertSame(get(mem, 12, 4), 1731 [33, 36, 39, 42]); 1732 1733 // This should be vector@0 - vector@16 + vector@0 1734 ins.exports.runif(0); 1735 assertSame(get(mem, 12, 4), 1736 [-9, -8, -7, -6]); 1737 1738 // This should be vector@0 + vector@16 + vector@32 1739 ins.exports.runblock(); 1740 assertSame(get(mem, 12, 4), 1741 [33, 36, 39, 42]); 1742 1743 // This should be vector@0 + vector@16 + N * vector@32 where 1744 // N is the parameter to runloop. 1745 ins.exports.runloop(3); 1746 assertSame(get(mem, 12, 4), 1747 [12+3*21, 14+3*22, 16+3*23, 18+3*24]);