tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ad-hack-extra.js (26792B)


      1 // |jit-test| skip-if: !wasmSimdEnabled()
      2 
      3 // Do not include this in the preamble, it must be loaded after lib/wasm.js
      4 load(scriptdir + "ad-hack-preamble.js")
      5 
      6 // Widening multiplication.
      7 // This is to be moved into ad-hack.js
      8 //
      9 //   (iMxN.extmul_{high,low}_iKxL_{s,u} A B)
     10 //
     11 // is equivalent to
     12 //
     13 //   (iMxN.mul (iMxN.extend_{high,low}_iKxL_{s,u} A)
     14 //             (iMxN.extend_{high,low}_iKxL_{s,u} B))
     15 //
     16 // It doesn't really matter what the inputs are, we can test this almost
     17 // blindly.
     18 //
     19 // Unfortunately, we do not yet have i64x2.extend_* so we introduce a helper
     20 // function to compute that.
     21 
     22 function makeExtMulTest(wide, narrow, part, signed) {
     23    let widener = (wide == 'i64x2') ?
     24        `call $${wide}_extend_${part}_${narrow}_${signed}` :
     25        `${wide}.extend_${part}_${narrow}_${signed}`;
     26    return `
     27    (func (export "${wide}_extmul_${part}_${narrow}_${signed}")
     28      (v128.store (i32.const 0)
     29         (${wide}.extmul_${part}_${narrow}_${signed} (v128.load (i32.const 16))
     30                                                     (v128.load (i32.const 32))))
     31      (v128.store (i32.const 48)
     32         (${wide}.mul (${widener} (v128.load (i32.const 16)))
     33                      (${widener} (v128.load (i32.const 32))))))
     34 `;
     35 }
     36 
     37 var ins = wasmEvalText(`
     38  (module
     39    (memory (export "mem") 1 1)
     40    (func $i64x2_extend_low_i32x4_s (param v128) (result v128)
     41      (i64x2.shr_s (i8x16.shuffle 16 16 16 16 0 1 2 3 16 16 16 16 4 5 6 7
     42                                  (local.get 0)
     43                                  (v128.const i32x4 0 0 0 0))
     44                   (i32.const 32)))
     45    (func $i64x2_extend_high_i32x4_s (param v128) (result v128)
     46      (i64x2.shr_s (i8x16.shuffle 16 16 16 16 8 9 10 11 16 16 16 16 12 13 14 15
     47                                  (local.get 0)
     48                                  (v128.const i32x4 0 0 0 0))
     49                   (i32.const 32)))
     50    (func $i64x2_extend_low_i32x4_u (param v128) (result v128)
     51      (i8x16.shuffle 0 1 2 3 16 16 16 16 4 5 6 7 16 16 16 16
     52                     (local.get 0)
     53                     (v128.const i32x4 0 0 0 0)))
     54    (func $i64x2_extend_high_i32x4_u (param v128) (result v128)
     55      (i8x16.shuffle 8 9 10 11 16 16 16 16 12 13 14 15 16 16 16 16
     56                     (local.get 0)
     57                     (v128.const i32x4 0 0 0 0)))
     58    ${makeExtMulTest('i64x2','i32x4','low','s')}
     59    ${makeExtMulTest('i64x2','i32x4','high','s')}
     60    ${makeExtMulTest('i64x2','i32x4','low','u')}
     61    ${makeExtMulTest('i64x2','i32x4','high','u')}
     62    ${makeExtMulTest('i32x4','i16x8','low','s')}
     63    ${makeExtMulTest('i32x4','i16x8','high','s')}
     64    ${makeExtMulTest('i32x4','i16x8','low','u')}
     65    ${makeExtMulTest('i32x4','i16x8','high','u')}
     66    ${makeExtMulTest('i16x8','i8x16','low','s')}
     67    ${makeExtMulTest('i16x8','i8x16','high','s')}
     68    ${makeExtMulTest('i16x8','i8x16','low','u')}
     69    ${makeExtMulTest('i16x8','i8x16','high','u')})`);
     70 
     71 for ( let [ WideArray, NarrowArray ] of
     72      [ [ Int16Array, Int8Array ],
     73        [ Int32Array, Int16Array ],
     74        [ BigInt64Array, Int32Array ] ] ) {
     75    let narrowMem = new NarrowArray(ins.exports.mem.buffer);
     76    let narrowSrc0 = 16/NarrowArray.BYTES_PER_ELEMENT;
     77    let narrowSrc1 = 32/NarrowArray.BYTES_PER_ELEMENT;
     78    let wideMem = new WideArray(ins.exports.mem.buffer);
     79    let wideElems = 16/WideArray.BYTES_PER_ELEMENT;
     80    let wideRes0 = 0;
     81    let wideRes1 = 48/WideArray.BYTES_PER_ELEMENT;
     82    let zero = iota(wideElems).map(_ => 0);
     83    for ( let part of [ 'low', 'high' ] ) {
     84        for ( let signed of [ 's', 'u' ] ) {
     85            for ( let [a, b] of cross(NarrowArray.inputs) ) {
     86                set(wideMem, wideRes0, zero);
     87                set(wideMem, wideRes1, zero);
     88                set(narrowMem, narrowSrc0, a);
     89                set(narrowMem, narrowSrc1, b);
     90                let test = `${WideArray.layoutName}_extmul_${part}_${NarrowArray.layoutName}_${signed}`;
     91                ins.exports[test]();
     92                assertSame(get(wideMem, wideRes0, wideElems),
     93                           get(wideMem, wideRes1, wideElems));
     94            }
     95        }
     96    }
     97 }
     98 
     99 // Bitmask.  Ion constant folds, so test that too.
    100 // This is to be merged into the existing bitmask tests in ad-hack.js.
    101 
    102 var ins = wasmEvalText(`
    103  (module
    104    (memory (export "mem") 1 1)
    105    (func (export "bitmask_i64x2") (result i32)
    106      (i64x2.bitmask (v128.load (i32.const 16))))
    107    (func (export "const_bitmask_i64x2") (result i32)
    108      (i64x2.bitmask (v128.const i64x2 0xff337f8012345678 0x0001984212345678))))`);
    109 
    110 var mem8 = new Uint8Array(ins.exports.mem.buffer);
    111 var mem64 = new BigUint64Array(ins.exports.mem.buffer);
    112 
    113 set(mem8, 16, iota(16).map((_) => 0));
    114 assertEq(ins.exports.bitmask_i64x2(), 0);
    115 
    116 set(mem64, 2, [0x8000000000000000n, 0x8000000000000000n]);
    117 assertEq(ins.exports.bitmask_i64x2(), 3);
    118 
    119 set(mem64, 2, [0x7FFFFFFFFFFFFFFFn, 0x7FFFFFFFFFFFFFFFn]);
    120 assertEq(ins.exports.bitmask_i64x2(), 0);
    121 
    122 set(mem64, 2, [0n, 0x8000000000000000n]);
    123 assertEq(ins.exports.bitmask_i64x2(), 2);
    124 
    125 set(mem64, 2, [0x8000000000000000n, 0n]);
    126 assertEq(ins.exports.bitmask_i64x2(), 1);
    127 
    128 assertEq(ins.exports.const_bitmask_i64x2(), 1);
    129 
    130 // Widen low/high.
    131 // This is to be merged into the existing widening tests in ad-hack.js.
    132 
    133 var ins = wasmEvalText(`
    134  (module
    135    (memory (export "mem") 1 1)
    136    (func (export "extend_low_i32x4_s")
    137      (v128.store (i32.const 0) (i64x2.extend_low_i32x4_s (v128.load (i32.const 16)))))
    138    (func (export "extend_high_i32x4_s")
    139      (v128.store (i32.const 0) (i64x2.extend_high_i32x4_s (v128.load (i32.const 16)))))
    140    (func (export "extend_low_i32x4_u")
    141      (v128.store (i32.const 0) (i64x2.extend_low_i32x4_u (v128.load (i32.const 16)))))
    142    (func (export "extend_high_i32x4_u")
    143      (v128.store (i32.const 0) (i64x2.extend_high_i32x4_u (v128.load (i32.const 16))))))`);
    144 
    145 var mem32 = new Int32Array(ins.exports.mem.buffer);
    146 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    147 var mem64u = new BigUint64Array(ins.exports.mem.buffer);
    148 
    149 var as = [205, 1, 192, 3].map((x) => x << 24);
    150 set(mem32, 4, as);
    151 
    152 ins.exports.extend_low_i32x4_s();
    153 assertSame(get(mem64, 0, 2), iota(2).map((n) => BigInt(as[n])))
    154 
    155 ins.exports.extend_high_i32x4_s();
    156 assertSame(get(mem64, 0, 2), iota(2).map((n) => BigInt(as[n+2])));
    157 
    158 ins.exports.extend_low_i32x4_u();
    159 assertSame(get(mem64u, 0, 2), iota(2).map((n) => BigInt(as[n] >>> 0)));
    160 
    161 ins.exports.extend_high_i32x4_u();
    162 assertSame(get(mem64u, 0, 2), iota(2).map((n) => BigInt(as[n+2] >>> 0)));
    163 
    164 // Saturating rounding q-format multiplication.
    165 // This is to be moved into ad-hack.js
    166 
    167 var ins = wasmEvalText(`
    168  (module
    169    (memory (export "mem") 1 1)
    170    (func (export "q15mulr_sat_s")
    171      (v128.store (i32.const 0) (i16x8.q15mulr_sat_s (v128.load (i32.const 16)) (v128.load (i32.const 32))))))`);
    172 
    173 var mem16 = new Int16Array(ins.exports.mem.buffer);
    174 for ( let [as, bs] of cross(Int16Array.inputs) ) {
    175    set(mem16, 8, as);
    176    set(mem16, 16, bs);
    177    ins.exports.q15mulr_sat_s();
    178    assertSame(get(mem16, 0, 8),
    179               iota(8).map((i) => signed_saturate((as[i] * bs[i] + 0x4000) >> 15, 16)));
    180 }
    181 
    182 
    183 // i64.all_true
    184 
    185 var ins = wasmEvalText(`
    186  (module
    187    (memory (export "mem") 1 1)
    188    (func (export "i64_all_true") (result i32)
    189      (i64x2.all_true (v128.load (i32.const 16)) ) ) )`);
    190 
    191 var mem32 = new Int32Array(ins.exports.mem.buffer);
    192 
    193 set(mem32, 4, [0, 0, 0, 0]);
    194 assertEq(0, ins.exports.i64_all_true());
    195 set(mem32, 4, [1, 0, 0, 0]);
    196 assertEq(0, ins.exports.i64_all_true());
    197 set(mem32, 4, [1, 0, 0, 1]);
    198 assertEq(1, ins.exports.i64_all_true());
    199 set(mem32, 4, [0, 0, 10, 0]);
    200 assertEq(0, ins.exports.i64_all_true());
    201 set(mem32, 4, [0, -250, 1, 0]);
    202 assertEq(1, ins.exports.i64_all_true());
    203 set(mem32, 4, [-1, -1, -1, -1]);
    204 assertEq(1, ins.exports.i64_all_true());
    205 
    206 if (this.wasmSimdAnalysis && wasmCompileMode() == "ion") {
    207  const positive =
    208      wasmCompile(
    209          `(module
    210              (memory (export "mem") 1 1)
    211              (func $f (param v128) (result i32)
    212                  (if (result i32) (i64x2.all_true (local.get 0))
    213                      (then (i32.const 42))
    214                      (else (i32.const 37))))
    215              (func (export "run") (result i32)
    216                (call $f (v128.load (i32.const 16)))))`);
    217  assertEq(wasmSimdAnalysis(), "simd128-to-scalar-and-branch -> folded");
    218 
    219  const negative =
    220      wasmCompile(
    221          `(module
    222              (memory (export "mem") 1 1)
    223              (func $f (param v128) (result i32)
    224                  (if (result i32) (i32.eqz (i64x2.all_true (local.get 0)))
    225                      (then (i32.const 42))
    226                      (else (i32.const 37))))
    227              (func (export "run") (result i32)
    228                (call $f (v128.load (i32.const 16)))))`);
    229  assertEq(wasmSimdAnalysis(), "simd128-to-scalar-and-branch -> folded");
    230 
    231  for ( let inp of [[1n, 2n], [4n, 0n], [0n, 0n]]) {
    232      const all_true = inp.every(v => v != 0n)
    233      let mem = new BigInt64Array(positive.exports.mem.buffer);
    234      set(mem, 2, inp);
    235      assertEq(positive.exports.run(), all_true ? 42 : 37);
    236 
    237      mem = new BigInt64Array(negative.exports.mem.buffer);
    238      set(mem, 2, inp);
    239      assertEq(negative.exports.run(), all_true ? 37 : 42);
    240  }
    241 
    242  wasmCompile(`(module (func (result i32) (i64x2.all_true (v128.const i64x2 0 0))))`);
    243  assertEq(wasmSimdAnalysis(), "simd128-to-scalar -> constant folded");
    244 }
    245 
    246 
    247 // i64x2.eq and i64x2.ne
    248 
    249 var ins = wasmEvalText(`
    250  (module
    251    (memory (export "mem") 1 1)
    252    (func (export "i64_eq")
    253      (v128.store (i32.const 0)
    254        (i64x2.eq (v128.load (i32.const 16)) (v128.load (i32.const 32))) ))
    255    (func (export "i64_ne")
    256      (v128.store (i32.const 0)
    257         (i64x2.ne (v128.load (i32.const 16)) (v128.load (i32.const 32))) )) )`);
    258 
    259 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    260 
    261 set(mem64, 2, [0n, 1n, 0n, 1n]);
    262 ins.exports.i64_eq();
    263 assertSame(get(mem64, 0, 2), [-1n, -1n]);
    264 ins.exports.i64_ne();
    265 assertSame(get(mem64, 0, 2), [0n, 0n]);
    266 set(mem64, 2, [0x0n, -1n, 0x100000000n, -1n]);
    267 ins.exports.i64_eq();
    268 assertSame(get(mem64, 0, 2), [0n, -1n]);
    269 set(mem64, 2, [-1n, 0x0n, -1n, 0x100000000n]);
    270 ins.exports.i64_ne();
    271 assertSame(get(mem64, 0, 2), [0n, -1n]);
    272 
    273 
    274 // i64x2.lt, i64x2.gt, i64x2.le, and i64.ge
    275 
    276 var ins = wasmEvalText(`
    277  (module
    278    (memory (export "mem") 1 1)
    279    (func (export "i64_lt_s")
    280      (v128.store (i32.const 0)
    281        (i64x2.lt_s (v128.load (i32.const 16)) (v128.load (i32.const 32))) ))
    282    (func (export "i64_gt_s")
    283      (v128.store (i32.const 0)
    284        (i64x2.gt_s (v128.load (i32.const 16)) (v128.load (i32.const 32))) ))
    285    (func (export "i64_le_s")
    286      (v128.store (i32.const 0)
    287        (i64x2.le_s (v128.load (i32.const 16)) (v128.load (i32.const 32))) ))
    288    (func (export "i64_ge_s")
    289      (v128.store (i32.const 0)
    290        (i64x2.ge_s (v128.load (i32.const 16)) (v128.load (i32.const 32))) )) )`);
    291 
    292 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    293 
    294 set(mem64, 2, [0n, 1n, 1n, 0n]);
    295 ins.exports.i64_lt_s();
    296 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    297 ins.exports.i64_gt_s();
    298 assertSame(get(mem64, 0, 2), [0n, -1n]);
    299 ins.exports.i64_le_s();
    300 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    301 ins.exports.i64_ge_s();
    302 assertSame(get(mem64, 0, 2), [0n, -1n]);
    303 
    304 set(mem64, 2, [0n, -1n, -1n, 0n]);
    305 ins.exports.i64_lt_s();
    306 assertSame(get(mem64, 0, 2), [0n, -1n]);
    307 ins.exports.i64_gt_s();
    308 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    309 ins.exports.i64_le_s();
    310 assertSame(get(mem64, 0, 2), [0n, -1n]);
    311 ins.exports.i64_ge_s();
    312 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    313 
    314 set(mem64, 2, [-2n, 2n, -1n, 1n]);
    315 ins.exports.i64_lt_s();
    316 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    317 ins.exports.i64_gt_s();
    318 assertSame(get(mem64, 0, 2), [0n, -1n]);
    319 ins.exports.i64_le_s();
    320 assertSame(get(mem64, 0, 2), [-1n, 0n]);
    321 ins.exports.i64_ge_s();
    322 assertSame(get(mem64, 0, 2), [0n, -1n]);
    323 
    324 set(mem64, 2, [-2n, 1n, -2n, 1n]);
    325 ins.exports.i64_lt_s();
    326 assertSame(get(mem64, 0, 2), [0n, 0n]);
    327 ins.exports.i64_gt_s();
    328 assertSame(get(mem64, 0, 2), [0n, 0n]);
    329 ins.exports.i64_le_s();
    330 assertSame(get(mem64, 0, 2), [-1n, -1n]);
    331 ins.exports.i64_ge_s();
    332 assertSame(get(mem64, 0, 2), [-1n, -1n]);
    333 
    334 
    335 function wasmCompile(text) {
    336  return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(text)))
    337 }
    338 
    339 
    340 // i64x2.abs
    341 
    342 var ins = wasmEvalText(`
    343  (module
    344    (memory (export "mem") 1 1)
    345    (func (export "i64_abs")
    346      (v128.store (i32.const 0)
    347        (i64x2.abs (v128.load (i32.const 16))) )) )`);
    348 
    349 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    350 
    351 set(mem64, 2, [-3n, 42n]);
    352 ins.exports.i64_abs();
    353 assertSame(get(mem64, 0, 2), [3n, 42n]);
    354 set(mem64, 2, [0n, -0x8000000000000000n]);
    355 ins.exports.i64_abs();
    356 assertSame(get(mem64, 0, 2), [0n, -0x8000000000000000n]);
    357 
    358 
    359 // Load lane
    360 
    361 var ins = wasmEvalText(`
    362  (module
    363    (memory (export "mem") 1 1)
    364    ${iota(16).map(i => `(func (export "load8_lane_${i}") (param i32)
    365      (v128.store (i32.const 0)
    366        (v128.load8_lane offset=0 ${i} (local.get 0) (v128.load (i32.const 16)))))
    367    `).join('')}
    368    ${iota(8).map(i => `(func (export "load16_lane_${i}") (param i32)
    369    (v128.store (i32.const 0)
    370      (v128.load16_lane offset=0 ${i} (local.get 0) (v128.load (i32.const 16)))))
    371    `).join('')}
    372    ${iota(4).map(i => `(func (export "load32_lane_${i}") (param i32)
    373    (v128.store (i32.const 0)
    374      (v128.load32_lane offset=0 ${i} (local.get 0) (v128.load (i32.const 16)))))
    375    `).join('')}
    376    ${iota(2).map(i => `(func (export "load64_lane_${i}") (param i32)
    377    (v128.store (i32.const 0)
    378      (v128.load64_lane offset=0 ${i} (local.get 0) (v128.load (i32.const 16)))))
    379    `).join('')}
    380    (func (export "load_lane_const_and_align")
    381      (v128.store (i32.const 0)
    382        (v128.load64_lane offset=32 1 (i32.const 1)
    383          (v128.load32_lane offset=32 1 (i32.const 3)
    384            (v128.load16_lane offset=32 0 (i32.const 5)
    385              (v128.load (i32.const 16)))))
    386      ))
    387  )`);
    388 
    389 var mem8 = new Int8Array(ins.exports.mem.buffer);
    390 var mem32 = new Int32Array(ins.exports.mem.buffer);
    391 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    392 
    393 var as = [0x12345678, 0x23456789, 0x3456789A, 0x456789AB];
    394 set(mem32, 4, as); set(mem8, 32, [0xC2]);
    395 
    396 ins.exports["load8_lane_0"](32);
    397 assertSame(get(mem32, 0, 4), [0x123456C2, 0x23456789, 0x3456789A, 0x456789AB]);
    398 ins.exports["load8_lane_1"](32);
    399 assertSame(get(mem32, 0, 4), [0x1234C278, 0x23456789, 0x3456789A, 0x456789AB]);
    400 ins.exports["load8_lane_2"](32);
    401 assertSame(get(mem32, 0, 4), [0x12C25678, 0x23456789, 0x3456789A, 0x456789AB]);
    402 ins.exports["load8_lane_3"](32);
    403 assertSame(get(mem32, 0, 4), [0xC2345678|0, 0x23456789, 0x3456789A, 0x456789AB]);
    404 ins.exports["load8_lane_4"](32);
    405 assertSame(get(mem32, 0, 4), [0x12345678, 0x234567C2, 0x3456789A, 0x456789AB]);
    406 ins.exports["load8_lane_6"](32);
    407 assertSame(get(mem32, 0, 4), [0x12345678, 0x23C26789, 0x3456789A, 0x456789AB]);
    408 ins.exports["load8_lane_9"](32);
    409 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0x3456C29A, 0x456789AB]);
    410 ins.exports["load8_lane_14"](32);
    411 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0x3456789A, 0x45C289AB]);
    412 
    413 set(mem8, 32, [0xC2, 0xD1]);
    414 
    415 ins.exports["load16_lane_0"](32);
    416 assertSame(get(mem32, 0, 4), [0x1234D1C2, 0x23456789, 0x3456789A, 0x456789AB]);
    417 ins.exports["load16_lane_1"](32);
    418 assertSame(get(mem32, 0, 4), [0xD1C25678|0, 0x23456789, 0x3456789A, 0x456789AB]);
    419 ins.exports["load16_lane_2"](32);
    420 assertSame(get(mem32, 0, 4), [0x12345678, 0x2345D1C2, 0x3456789A, 0x456789AB]);
    421 ins.exports["load16_lane_5"](32);
    422 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0xD1C2789A|0, 0x456789AB]);
    423 ins.exports["load16_lane_7"](32);
    424 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0x3456789A, 0xD1C289AB|0]);
    425 
    426 set(mem32, 8, [0x16B5C3D0]);
    427 
    428 ins.exports["load32_lane_0"](32);
    429 assertSame(get(mem32, 0, 4), [0x16B5C3D0, 0x23456789, 0x3456789A, 0x456789AB]);
    430 ins.exports["load32_lane_1"](32);
    431 assertSame(get(mem32, 0, 4), [0x12345678, 0x16B5C3D0, 0x3456789A, 0x456789AB]);
    432 ins.exports["load32_lane_2"](32);
    433 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0x16B5C3D0, 0x456789AB]);
    434 ins.exports["load32_lane_3"](32);
    435 assertSame(get(mem32, 0, 4), [0x12345678, 0x23456789, 0x3456789A, 0x16B5C3D0]);
    436 
    437 set(mem64, 4, [0x3300AA4416B5C3D0n]);
    438 
    439 ins.exports["load64_lane_0"](32);
    440 assertSame(get(mem64, 0, 2), [0x3300AA4416B5C3D0n, 0x456789AB3456789An]);
    441 ins.exports["load64_lane_1"](32);
    442 assertSame(get(mem64, 0, 2), [0x2345678912345678n, 0x3300AA4416B5C3D0n]);
    443 
    444 // .. (mis)align load lane
    445 
    446 var as = [0x12345678, 0x23456789, 0x3456789A, 0x456789AB];
    447 set(mem32, 4, as); set(mem64, 4, [0x3300AA4416B5C3D0n, 0x300AA4416B5C3D03n]);
    448 
    449 ins.exports["load16_lane_5"](33);
    450 assertSame(get(mem32, 0, 4), [0x12345678,0x23456789,0xb5c3789a|0,0x456789ab]);
    451 ins.exports["load32_lane_1"](34);
    452 assertSame(get(mem32, 0, 4), [0x12345678, 0xaa4416b5|0,0x3456789a,0x456789ab]);
    453 ins.exports["load64_lane_0"](35);
    454 assertSame(get(mem64, 0, 2), [0x5c3d033300aa4416n, 0x456789ab3456789an]);
    455 
    456 ins.exports["load_lane_const_and_align"]();
    457 assertSame(get(mem32, 0, 4), [0x123400aa,0x00AA4416,0x4416b5c3,0x033300aa]);
    458 
    459 // Store lane
    460 
    461 var ins = wasmEvalText(`
    462  (module
    463    (memory (export "mem") 1 1)
    464    ${iota(16).map(i => `(func (export "store8_lane_${i}") (param i32) (param i32)
    465      (v128.store8_lane ${i} (local.get 1) (v128.load (local.get 0))))
    466    `).join('')}
    467    ${iota(8).map(i => `(func (export "store16_lane_${i}") (param i32) (param i32)
    468      (v128.store16_lane ${i} (local.get 1) (v128.load (local.get 0))))
    469    `).join('')}
    470    ${iota(4).map(i => `(func (export "store32_lane_${i}") (param i32) (param i32)
    471      (v128.store32_lane ${i} (local.get 1) (v128.load (local.get 0))))
    472    `).join('')}
    473    ${iota(2).map(i => `(func (export "store64_lane_${i}") (param i32) (param i32)
    474      (v128.store64_lane ${i} (local.get 1) (v128.load (local.get 0))))
    475    `).join('')}
    476    (func (export "store_lane_const_and_align")
    477      (v128.store16_lane 1 (i32.const 33) (v128.load (i32.const 16)))
    478      (v128.store32_lane 2 (i32.const 37) (v128.load (i32.const 16)))
    479      (v128.store64_lane 0 (i32.const 47) (v128.load (i32.const 16)))
    480    ))`);
    481 
    482 
    483 var mem8 = new Int8Array(ins.exports.mem.buffer);
    484 var mem32 = new Int32Array(ins.exports.mem.buffer);
    485 var mem64 = new BigInt64Array(ins.exports.mem.buffer);
    486 
    487 var as = [0x12345678, 0x23456789, 0x3456789A, 0x456789AB];
    488 set(mem32, 4, as); set(mem32, 0, [0x7799AA00, 42, 3, 0]);
    489 
    490 ins.exports["store8_lane_0"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA78]);
    491 ins.exports["store8_lane_1"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA56]);
    492 ins.exports["store8_lane_2"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA34]);
    493 ins.exports["store8_lane_3"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA12]);
    494 ins.exports["store8_lane_5"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA67]);
    495 ins.exports["store8_lane_7"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA23]);
    496 ins.exports["store8_lane_8"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA9A]);
    497 ins.exports["store8_lane_15"](16, 0); assertSame(get(mem32, 0, 1), [0x7799AA45]);
    498 
    499 ins.exports["store16_lane_0"](16, 0); assertSame(get(mem32, 0, 1), [0x77995678]);
    500 ins.exports["store16_lane_1"](16, 0); assertSame(get(mem32, 0, 1), [0x77991234]);
    501 ins.exports["store16_lane_2"](16, 0); assertSame(get(mem32, 0, 1), [0x77996789]);
    502 ins.exports["store16_lane_5"](16, 0); assertSame(get(mem32, 0, 1), [0x77993456]);
    503 ins.exports["store16_lane_7"](16, 0); assertSame(get(mem32, 0, 1), [0x77994567]);
    504 
    505 ins.exports["store32_lane_0"](16, 0); assertSame(get(mem32, 0, 2), [0x12345678, 42]);
    506 ins.exports["store32_lane_1"](16, 0); assertSame(get(mem32, 0, 2), [0x23456789, 42]);
    507 ins.exports["store32_lane_2"](16, 0); assertSame(get(mem32, 0, 2), [0x3456789A, 42]);
    508 ins.exports["store32_lane_3"](16, 0); assertSame(get(mem32, 0, 2), [0x456789AB, 42]);
    509 
    510 ins.exports["store64_lane_0"](16, 0); assertSame(get(mem64, 0, 2), [0x2345678912345678n, 3]);
    511 ins.exports["store64_lane_1"](16, 0); assertSame(get(mem64, 0, 2), [0x456789AB3456789An, 3]);
    512 
    513 // .. (mis)align store lane
    514 
    515 var as = [0x12345678, 0x23456789, 0x3456789A, 0x456789AB];
    516 set(mem32, 4, as); set(mem32, 0, [0x7799AA01, 42, 3, 0]);
    517 ins.exports["store16_lane_1"](16, 1); assertSame(get(mem32, 0, 2), [0x77123401, 42]);
    518 set(mem32, 0, [0x7799AA01, 42, 3, 0]);
    519 ins.exports["store32_lane_1"](16, 2); assertSame(get(mem32, 0, 2), [0x6789AA01, 0x2345]);
    520 set(mem32, 0, [0x7799AA01, 42, 5, 3]);
    521 ins.exports["store64_lane_0"](16, 1);
    522 assertSame(get(mem64, 0, 2), [0x4567891234567801n, 0x0300000023]);
    523 
    524 set(mem32, 4, [
    525  0x12345678, 0x23456789, 0x3456789A, 0x456789AB,
    526  0x55AA55AA, 0xCC44CC44, 0x55AA55AA, 0xCC44CC44,
    527  0x55AA55AA, 0xCC44CC44, 0x55AA55AA, 0xCC44CC44,
    528 ]);
    529 ins.exports["store_lane_const_and_align"]();
    530 assertSame(get(mem32, 8, 8), [
    531  0x551234aa, 0x56789a44, 0x55aa5534, 0x7844cc44,
    532  0x89123456|0, 0xcc234567|0, 0x55aa55aa, 0xcc44cc44|0,
    533 ]);
    534 
    535 
    536 // i8x16.popcnt
    537 
    538 var ins = wasmEvalText(`
    539  (module
    540    (memory (export "mem") 1 1)
    541    (func (export "i8x16_popcnt")
    542      (v128.store (i32.const 0) (i8x16.popcnt (v128.load (i32.const 16)) )))
    543  )`);
    544 
    545 var mem8 = new Int8Array(ins.exports.mem.buffer);
    546 
    547 set(mem8, 16, [0, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 3, -1, 0xF0, 0x11, 0xFE, 0x0F, 0xE]);
    548 ins.exports.i8x16_popcnt();
    549 assertSame(get(mem8, 0, 16), [0,1,1,1,1,1,1,1,1,2,8,4,2,7,4,3]);
    550 
    551 
    552 /// Double-precision conversion instructions.
    553 /// f64x2.convert_low_i32x4_{u,s} / i32x4.trunc_sat_f64x2_{u,s}_zero
    554 /// f32x4.demote_f64x2_zero / f64x2.promote_low_f32x4
    555 
    556 var ins = wasmEvalText(`
    557  (module
    558    (memory (export "mem") 1 1)
    559    (func (export "f64x2_convert_low_i32x4_s")
    560      (v128.store (i32.const 0) (f64x2.convert_low_i32x4_s (v128.load (i32.const 16)) )))
    561    (func (export "f64x2_convert_low_i32x4_u")
    562      (v128.store (i32.const 0) (f64x2.convert_low_i32x4_u (v128.load (i32.const 16)) )))
    563 
    564    (func (export "i32x4_trunc_sat_f64x2_s_zero")
    565      (v128.store (i32.const 0) (i32x4.trunc_sat_f64x2_s_zero (v128.load (i32.const 16)) )))
    566    (func (export "i32x4_trunc_sat_f64x2_u_zero")
    567      (v128.store (i32.const 0) (i32x4.trunc_sat_f64x2_u_zero (v128.load (i32.const 16)) )))
    568 
    569    (func (export "f32x4_demote_f64x2")
    570      (v128.store (i32.const 0) (f32x4.demote_f64x2_zero (v128.load (i32.const 16)) )))
    571    (func (export "f64x2_protomote_f32x4")
    572      (v128.store (i32.const 0) (f64x2.promote_low_f32x4 (v128.load (i32.const 16)) )))
    573  )`);
    574 
    575 var mem32 = new Int32Array(ins.exports.mem.buffer);
    576 var memU32 = new Uint32Array(ins.exports.mem.buffer);
    577 var memF32 = new Float32Array(ins.exports.mem.buffer);
    578 var memF64 = new Float64Array(ins.exports.mem.buffer);
    579 
    580 // f64x2.convert_low_i32x4_u / f64x2.convert_low_i32x4_s
    581 
    582 set(mem32, 4, [1, -2, 0, -2]);
    583 ins.exports.f64x2_convert_low_i32x4_s();
    584 assertSame(get(memF64, 0, 2), [1, -2]);
    585 set(mem32, 4, [-1, 0, 5, -212312312]);
    586 ins.exports.f64x2_convert_low_i32x4_s();
    587 assertSame(get(memF64, 0, 2), [-1, 0]);
    588 
    589 set(memU32, 4, [1, 4045646797, 4, 0]);
    590 ins.exports.f64x2_convert_low_i32x4_u();
    591 assertSame(get(memF64, 0, 2), [1, 4045646797]);
    592 set(memU32, 4, [0, 2, 4, 3]);
    593 ins.exports.f64x2_convert_low_i32x4_u();
    594 assertSame(get(memF64, 0, 2), [0, 2]);
    595 
    596 // i32x4.trunc_sat_f64x2_u_zero / i32x4.trunc_sat_f64x2_s_zero
    597 
    598 set(memF64, 2, [0,0])
    599 ins.exports.i32x4_trunc_sat_f64x2_s_zero();
    600 assertSame(get(mem32, 0, 4), [0,0,0,0]);
    601 ins.exports.i32x4_trunc_sat_f64x2_u_zero();
    602 assertSame(get(memU32, 0, 4), [0,0,0,0]);
    603 
    604 set(memF64, 2, [-1.23,65535.12])
    605 ins.exports.i32x4_trunc_sat_f64x2_s_zero();
    606 assertSame(get(mem32, 0, 4), [-1,65535,0,0]);
    607 set(memF64, 2, [1.99,65535.12])
    608 ins.exports.i32x4_trunc_sat_f64x2_u_zero();
    609 assertSame(get(memU32, 0, 4), [1,65535,0,0]);
    610 
    611 set(memF64, 2, [10e+100,-10e+100])
    612 ins.exports.i32x4_trunc_sat_f64x2_s_zero();
    613 assertSame(get(mem32, 0, 4), [0x7fffffff,-0x80000000,0,0]);
    614 ins.exports.i32x4_trunc_sat_f64x2_u_zero();
    615 assertSame(get(memU32, 0, 4), [0xffffffff,0,0,0]);
    616 
    617 // f32x4.demote_f64x2_zero
    618 
    619 set(memF64, 2, [1, 2])
    620 ins.exports.f32x4_demote_f64x2();
    621 assertSame(get(memF32, 0, 4), [1,2,0,0]);
    622 
    623 set(memF64, 2, [-4e38, 4e38])
    624 ins.exports.f32x4_demote_f64x2();
    625 assertSame(get(memF32, 0, 4), [-Infinity,Infinity,0,0]);
    626 
    627 set(memF64, 2, [-1e-46, 1e-46])
    628 ins.exports.f32x4_demote_f64x2();
    629 assertSame(get(memF32, 0, 4), [1/-Infinity,0,0,0]);
    630 
    631 set(memF64, 2, [0, NaN])
    632 ins.exports.f32x4_demote_f64x2();
    633 assertSame(get(memF32, 0, 4), [0, NaN,0,0]);
    634 
    635 set(memF64, 2, [Infinity, -Infinity])
    636 ins.exports.f32x4_demote_f64x2();
    637 assertSame(get(memF32, 0, 4), [Infinity, -Infinity,0,0]);
    638 
    639 // f64x2.promote_low_f32x4
    640 
    641 set(memF32, 4, [4, 3, 1, 2])
    642 ins.exports.f64x2_protomote_f32x4();
    643 assertSame(get(memF64, 0, 2), [4, 3]);
    644 
    645 set(memF32, 4, [NaN, 0, 0, 0])
    646 ins.exports.f64x2_protomote_f32x4();
    647 assertSame(get(memF64, 0, 2), [NaN, 0]);
    648 
    649 set(memF32, 4, [Infinity, -Infinity, 0, 0])
    650 ins.exports.f64x2_protomote_f32x4();
    651 assertSame(get(memF64, 0, 2), [Infinity, -Infinity]);
    652 
    653 
    654 // i16x8.extadd_pairwise_i8x16_{s,u} / i32x4.extadd_pairwise_i16x8_{s,u}
    655 
    656 var ins = wasmEvalText(`
    657  (module
    658    (memory (export "mem") 1 1)
    659    (func (export "i16x8_extadd_pairwise_i8x16_s")
    660      (v128.store (i32.const 0) (i16x8.extadd_pairwise_i8x16_s (v128.load (i32.const 16)) )))
    661    (func (export "i16x8_extadd_pairwise_i8x16_u")
    662      (v128.store (i32.const 0) (i16x8.extadd_pairwise_i8x16_u (v128.load (i32.const 16)) )))
    663 
    664    (func (export "i32x4_extadd_pairwise_i16x8_s")
    665      (v128.store (i32.const 0) (i32x4.extadd_pairwise_i16x8_s (v128.load (i32.const 16)) )))
    666    (func (export "i32x4_extadd_pairwise_i16x8_u")
    667      (v128.store (i32.const 0) (i32x4.extadd_pairwise_i16x8_u (v128.load (i32.const 16)) )))
    668  )`);
    669 
    670 var mem8 = new Int8Array(ins.exports.mem.buffer);
    671 var memU8 = new Uint8Array(ins.exports.mem.buffer);
    672 var mem16 = new Int16Array(ins.exports.mem.buffer);
    673 var memU16 = new Uint16Array(ins.exports.mem.buffer);
    674 var mem32 = new Int32Array(ins.exports.mem.buffer);
    675 var memU32 = new Uint32Array(ins.exports.mem.buffer);
    676 
    677 set(mem8, 16, [0, 0, 1, 1, 2, -2, 0, 42, 1, -101, 101, -1, 127, 125, -1, -2]);
    678 ins.exports.i16x8_extadd_pairwise_i8x16_s();
    679 assertSame(get(mem16, 0, 8), [0, 2, 0, 42, -100, 100, 252, -3]);
    680 
    681 set(memU8, 16, [0, 0, 1, 1, 2, 255, 0, 42, 0, 255, 254, 0, 127, 125, 255, 255]);
    682 ins.exports.i16x8_extadd_pairwise_i8x16_u();
    683 assertSame(get(memU16, 0, 8), [0, 2, 257, 42, 255, 254, 252, 510]);
    684 
    685 set(mem16, 8, [0, 0, 1, 1, 2, -2, -1, -2]);
    686 ins.exports.i32x4_extadd_pairwise_i16x8_s();
    687 assertSame(get(mem32, 0, 4), [0, 2, 0, -3]);
    688 set(mem16, 8, [0, 42, 1, -32760, 32766, -1, 32761, 32762]);
    689 ins.exports.i32x4_extadd_pairwise_i16x8_s();
    690 assertSame(get(mem32, 0, 4), [42, -32759, 32765, 65523]);
    691 
    692 set(memU16, 8, [0, 0, 1, 1, 2, 65535, 65535, 65535]);
    693 ins.exports.i32x4_extadd_pairwise_i16x8_u();
    694 assertSame(get(memU32, 0, 4), [0, 2, 65537, 131070]);
    695 set(memU16, 8, [0, 42, 0, 65535, 65534, 0, 32768, 32765]);
    696 ins.exports.i32x4_extadd_pairwise_i16x8_u();
    697 assertSame(get(memU32, 0, 4), [42, 65535, 65534, 65533]);