tor-browser

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

relaxed-fma.js (16497B)


      1 // |jit-test| --setpref=wasm_relaxed_simd=true; skip-if: !wasmRelaxedSimdEnabled()
      2 
      3 // Experimental opcodes.  We have no text parsing support for these yet.  The
      4 // tests will be cleaned up and moved into ad-hack.js if the opcodes are
      5 // adopted.
      6 
      7 load(libdir + "wasm-binary.js");
      8 
      9 function wasmEval(bytes, imports) {
     10    return new WebAssembly.Instance(new WebAssembly.Module(bytes), imports);
     11 }
     12 
     13 function wasmValidateAndEval(bytes, imports) {
     14    assertEq(WebAssembly.validate(bytes), true, "test of WasmValidate.cpp");
     15    return wasmEval(bytes, imports);
     16 }
     17 
     18 function get(arr, loc, len) {
     19    let res = [];
     20    for ( let i=0; i < len; i++ ) {
     21        res.push(arr[loc+i]);
     22    }
     23    return res;
     24 }
     25 
     26 function set(arr, loc, vals) {
     27    for ( let i=0; i < vals.length; i++ ) {
     28        if (arr instanceof BigInt64Array) {
     29            arr[loc+i] = BigInt(vals[i]);
     30        } else {
     31            arr[loc+i] = vals[i];
     32        }
     33    }
     34 }
     35 
     36 const v2vSig = {args:[], ret:VoidCode};
     37 
     38 function V128Load(addr) {
     39    return [I32ConstCode, varS32(addr),
     40            SimdPrefix, V128LoadCode, 4, varU32(0)]
     41 }
     42 
     43 function V128StoreExpr(addr, v) {
     44    return [I32ConstCode, varS32(addr),
     45            ...v,
     46            SimdPrefix, V128StoreCode, 4, varU32(0)];
     47 }
     48 
     49 // FMA/FNMA, https://github.com/WebAssembly/relaxed-simd/issues/27 and
     50 // https://github.com/WebAssembly/relaxed-simd/pull/81
     51 
     52 function fma(x, y, a) { return (x * y) + a; }
     53 function fnma(x, y, a) { return - (x * y) + a; }
     54 
     55 var fxs = [10, 20, 30, 40];
     56 var fys = [-2, -3, -4, -5];
     57 var fas = [0, 100, 500, 700];
     58 var dxs = [10, 20];
     59 var dys = [-2, -3];
     60 var das = [0, 100];
     61 
     62 for ( let [opcode, xs, ys, as, operator] of [[F32x4RelaxedMaddCode, fxs, fys, fas, fma],
     63                                             [F32x4RelaxedNmaddCode, fxs, fys, fas, fnma],
     64                                             [F64x2RelaxedMaddCode, dxs, dys, das, fma],
     65                                             [F64x2RelaxedNmaddCode, dxs, dys, das, fnma]] ) {
     66    var k = xs.length;
     67    var ans = iota(k).map((i) => operator(xs[i], ys[i], as[i]))
     68 
     69    var ins = wasmValidateAndEval(moduleWithSections([
     70        sigSection([v2vSig]),
     71        declSection([0]),
     72        memorySection(1),
     73        exportSection([{funcIndex: 0, name: "run"},
     74                       {memIndex: 0, name: "mem"}]),
     75        bodySection([
     76            funcBody({locals:[],
     77                      body: [...V128StoreExpr(0, [...V128Load(16),
     78                                                  ...V128Load(32),
     79                                                  ...V128Load(48),
     80                                                  SimdPrefix, ...varU32(opcode)])]})])]));
     81 
     82    var mem = new (k == 4 ? Float32Array : Float64Array)(ins.exports.mem.buffer);
     83    set(mem, k, xs);
     84    set(mem, 2*k, ys);
     85    set(mem, 3*k, as);
     86    ins.exports.run();
     87    var result = get(mem, 0, k);
     88    assertSame(result, ans);
     89 
     90    assertEq(false, WebAssembly.validate(moduleWithSections([
     91        sigSection([v2vSig]),
     92        declSection([0]),
     93        memorySection(1),
     94        exportSection([{funcIndex: 0, name: "run"},
     95                       {memIndex: 0, name: "mem"}]),
     96        bodySection([
     97            funcBody({locals:[],
     98                      body: [...V128StoreExpr(0, [...V128Load(0),
     99                                                  ...V128Load(0),
    100                                                  SimdPrefix, ...varU32(opcode)])]})])])));
    101 }
    102 
    103 // Relaxed swizzle, https://github.com/WebAssembly/relaxed-simd/issues/22
    104 
    105 var ins = wasmValidateAndEval(moduleWithSections([
    106    sigSection([v2vSig]),
    107    declSection([0]),
    108    memorySection(1),
    109    exportSection([{funcIndex: 0, name: "run"},
    110                   {memIndex: 0, name: "mem"}]),
    111    bodySection([
    112        funcBody({locals:[],
    113                  body: [...V128StoreExpr(0, [...V128Load(16),
    114                                              ...V128Load(32),
    115                                              SimdPrefix, ...varU32(I8x16RelaxedSwizzleCode)])]})])]));
    116 var mem = new Uint8Array(ins.exports.mem.buffer);
    117 var test = [1, 4, 3, 7, 123, 0, 8, 222];
    118 set(mem, 16, test);
    119 for (let [i, s] of [[0, 0], [0, 1], [1,1], [1, 3], [7,5]]) {
    120    var ans = new Uint8Array(16);
    121    for (let j = 0; j < 16; j++) {
    122        mem[32 + j] = (j * s + i) & 15;
    123        ans[j] = test[(j * s + i) & 15];
    124    }
    125    ins.exports.run();
    126    var result = get(mem, 0, 16);
    127    assertSame(result, ans);
    128 }
    129 
    130 assertEq(false, WebAssembly.validate(moduleWithSections([
    131    sigSection([v2vSig]),
    132    declSection([0]),
    133    memorySection(1),
    134    bodySection([
    135        funcBody({locals:[],
    136            body: [...V128StoreExpr(0, [...V128Load(16),
    137                                        SimdPrefix, ...varU32(I8x16RelaxedSwizzleCode)])]})])])));
    138 
    139 
    140 // Relaxed MIN/MAX, https://github.com/WebAssembly/relaxed-simd/issues/33
    141 
    142 const Neg0 = -1/Infinity;
    143 var minMaxTests = [
    144    {a: 0, b: 0, min: 0, max: 0, },
    145    {a: Neg0, b: Neg0, min: Neg0, max: Neg0, },
    146    {a: 1/3, b: 2/3, min: 1/3, max: 2/3, },
    147    {a: -1/3, b: -2/3, min: -2/3, max: -1/3, },
    148    {a: -1000, b: 1, min: -1000, max: 1, },
    149    {a: 10, b: -2, min: -2, max: 10, },
    150 ];
    151 
    152 for (let k of [4, 2]) {
    153    const minOpcode = k == 4 ? F32x4RelaxedMinCode : F64x2RelaxedMinCode;
    154    const maxOpcode = k == 4 ? F32x4RelaxedMaxCode : F64x2RelaxedMaxCode;
    155 
    156    var ins = wasmValidateAndEval(moduleWithSections([
    157        sigSection([v2vSig]),
    158        declSection([0, 0]),
    159        memorySection(1),
    160        exportSection([{funcIndex: 0, name: "min"},
    161                       {funcIndex: 1, name: "max"},
    162                       {memIndex: 0, name: "mem"}]),
    163        bodySection([
    164            funcBody({locals:[],
    165                      body: [...V128StoreExpr(0, [...V128Load(16),
    166                                                  ...V128Load(32),
    167                                                  SimdPrefix, ...varU32(minOpcode)])]}),
    168            funcBody({locals:[],
    169                      body: [...V128StoreExpr(0, [...V128Load(16),
    170                                                  ...V128Load(32),
    171                                                  SimdPrefix, ...varU32(maxOpcode)])]})])]));
    172    for (let i = 0; i < minMaxTests.length; i++) {
    173        var Ty = k == 4 ? Float32Array : Float64Array;
    174        var mem = new Ty(ins.exports.mem.buffer);
    175        var minResult = new Ty(k);
    176        var maxResult = new Ty(k);
    177        for (let j = 0; j < k; j++) {
    178            const {a, b, min, max } = minMaxTests[(j + i) % minMaxTests.length];
    179            mem[j + k] = a;
    180            mem[j + k * 2] = b;
    181            minResult[j] = min;
    182            maxResult[j] = max;
    183        }
    184        ins.exports.min();
    185        var result = get(mem, 0, k);
    186        assertSame(result, minResult);
    187        ins.exports.max();
    188        var result = get(mem, 0, k);
    189        assertSame(result, maxResult);
    190    }
    191 
    192    for (let op of [minOpcode, maxOpcode]) {
    193        assertEq(false, WebAssembly.validate(moduleWithSections([
    194            sigSection([v2vSig]),
    195            declSection([0, 0]),
    196            memorySection(1),
    197            exportSection([]),
    198            bodySection([
    199                funcBody({locals:[],
    200                          body: [...V128StoreExpr(0, [...V128Load(0),
    201                                                      SimdPrefix, ...varU32(op)])]})])])));
    202    }
    203 }
    204 
    205 // Relaxed I32x4.TruncFXXX, https://github.com/WebAssembly/relaxed-simd/issues/21
    206 
    207 var ins = wasmValidateAndEval(moduleWithSections([
    208    sigSection([v2vSig]),
    209    declSection([0, 0, 0, 0]),
    210    memorySection(1),
    211    exportSection([{funcIndex: 0, name: "from32s"},
    212                   {funcIndex: 1, name: "from32u"},
    213                   {funcIndex: 2, name: "from64s"},
    214                   {funcIndex: 3, name: "from64u"},
    215                   {memIndex: 0, name: "mem"}]),
    216    bodySection([
    217        funcBody({locals:[],
    218                  body: [...V128StoreExpr(0, [...V128Load(16),
    219                                              SimdPrefix, ...varU32(I32x4RelaxedTruncSSatF32x4Code)])]}),
    220        funcBody({locals:[],
    221                  body: [...V128StoreExpr(0, [...V128Load(16),
    222                                              SimdPrefix, ...varU32(I32x4RelaxedTruncUSatF32x4Code)])]}),
    223        funcBody({locals:[],
    224                  body: [...V128StoreExpr(0, [...V128Load(16),
    225                                              SimdPrefix, ...varU32(I32x4RelaxedTruncSatF64x2SZeroCode)])]}),
    226        funcBody({locals:[],
    227                  body: [...V128StoreExpr(0, [...V128Load(16),
    228                                              SimdPrefix, ...varU32(I32x4RelaxedTruncSatF64x2UZeroCode)])]})])]));
    229 
    230 var mem = ins.exports.mem.buffer;
    231 set(new Float32Array(mem), 4, [0, 2.3, -3.4, 100000]);
    232 ins.exports.from32s();
    233 var result = get(new Int32Array(mem), 0, 4);
    234 assertSame(result, [0, 2, -3, 100000]);
    235 
    236 set(new Float32Array(mem), 4, [0, 3.3, 0x80000000, 200000]);
    237 ins.exports.from32u();
    238 var result = get(new Uint32Array(mem), 0, 4);
    239 assertSame(result, [0, 3, 0x80000000, 200000]);
    240 set(new Float32Array(mem), 4, [0, 0x80000100, 0x80000101, 0xFFFFFF00]);
    241 ins.exports.from32u();
    242 var result = get(new Uint32Array(mem), 0, 4);
    243 assertSame(result, [0, 0x80000100, 0x80000100, 0xFFFFFF00]);
    244 
    245 set(new Float64Array(mem), 2, [200000.3, -3.4]);
    246 ins.exports.from64s();
    247 var result = get(new Int32Array(mem), 0, 4);
    248 assertSame(result, [200000, -3, 0, 0]);
    249 set(new Float64Array(mem), 2, [0x90000000 + 0.1, 0]);
    250 ins.exports.from64u();
    251 var result = get(new Uint32Array(mem), 0, 4);
    252 assertSame(result, [0x90000000, 0, 0, 0]);
    253 
    254 for (let op of [I32x4RelaxedTruncSSatF32x4Code, I32x4RelaxedTruncUSatF32x4Code,
    255                I32x4RelaxedTruncSatF64x2SZeroCode, I32x4RelaxedTruncSatF64x2UZeroCode]) {
    256    assertEq(false, WebAssembly.validate(moduleWithSections([
    257        sigSection([v2vSig]),
    258        declSection([0]),
    259        memorySection(1),
    260        exportSection([]),
    261        bodySection([
    262            funcBody({locals:[],
    263                      body: [...V128StoreExpr(0, [SimdPrefix, ...varU32(op)])]})])])));
    264 }
    265 
    266 // Relaxed blend / laneselect, https://github.com/WebAssembly/relaxed-simd/issues/17
    267 
    268 for (let [k, opcode, AT] of [[1, I8x16RelaxedLaneSelectCode, Int8Array],
    269                             [2, I16x8RelaxedLaneSelectCode, Int16Array],
    270                             [4, I32x4RelaxedLaneSelectCode, Int32Array],
    271                             [8, I64x2RelaxedLaneSelectCode, BigInt64Array]]) {
    272 
    273    var ins = wasmValidateAndEval(moduleWithSections([
    274        sigSection([v2vSig]),
    275        declSection([0]),
    276        memorySection(1),
    277        exportSection([{funcIndex: 0, name: "run"},
    278                        {memIndex: 0, name: "mem"}]),
    279        bodySection([
    280            funcBody({locals:[],
    281                        body: [...V128StoreExpr(0, [...V128Load(16),
    282                                                    ...V128Load(32),
    283                                                    ...V128Load(48),
    284                                                    SimdPrefix, ...varU32(opcode)])]})])]));
    285 
    286    var mem = ins.exports.mem.buffer;
    287    var mem8 = new Uint8Array(mem);
    288    set(mem8, 16, [1,2,3,4,0,0,0,0,100,0,102,0,0,250,251,252,253]);
    289    set(mem8, 32, [0,0,0,0,5,6,7,8,0,101,0,103,0,254,255,0,1]);
    290    var c = new AT(mem, 48, 16 / k);
    291    for (let i = 0; i < c.length; i++) {
    292        // Use popcnt to randomize 0 and ~0 
    293        const popcnt_i = i.toString(2).replace(/0/g, "").length;
    294        const v = popcnt_i & 1 ? -1 : 0
    295        c[i] = k == 8 ? BigInt(v) : v;
    296    }
    297    ins.exports.run();
    298    for (let i = 0; i < 16; i++) {
    299        const r = c[(i / k) | 0] ? mem8[16 + i] : mem8[32 + i];
    300        assertEq(r, mem8[i]);
    301    }
    302 
    303    assertEq(false, WebAssembly.validate(moduleWithSections([
    304        sigSection([v2vSig]),
    305        declSection([0]),
    306        memorySection(1),
    307        exportSection([{funcIndex: 0, name: "run"},
    308                       {memIndex: 0, name: "mem"}]),
    309        bodySection([
    310            funcBody({locals:[],
    311                      body: [...V128StoreExpr(0, [...V128Load(0),
    312                                                  ...V128Load(0),
    313                                                  SimdPrefix, ...varU32(opcode)])]})])])));
    314 }
    315 
    316 
    317 // Relaxed rounding q-format multiplication.
    318 var ins = wasmValidateAndEval(moduleWithSections([
    319    sigSection([v2vSig]),
    320    declSection([0]),
    321    memorySection(1),
    322    exportSection([{funcIndex: 0, name: "relaxed_q15mulr_s"},
    323                    {memIndex: 0, name: "mem"}]),
    324    bodySection([
    325        funcBody({locals:[],
    326                    body: [...V128StoreExpr(0, [...V128Load(16),
    327                                                ...V128Load(32),
    328                                                SimdPrefix, ...varU32(I16x8RelaxedQ15MulrSCode)])]})])]));
    329 
    330 var mem16 = new Int16Array(ins.exports.mem.buffer);
    331 for (let [as, bs] of cross([
    332        [1, -3, 5, -7, 11, -13, -17, 19],
    333        [-1, 0, 16, -32, 64, 128, -1024, 0, 1],
    334        [1,2,-32768,32767,1,4,-32768,32767]]) ) {
    335    set(mem16, 8, as);
    336    set(mem16, 16, bs);
    337    ins.exports.relaxed_q15mulr_s();
    338    const result = get(mem16, 0, 8);
    339    for (let i = 0; i < 8; i++) {
    340        const expected = (as[i] * bs[i] + 0x4000) >> 15;
    341        if (as[i] == -32768 && bs[i] == -32768) continue;
    342        assertEq(expected, result[i], `result of ${as[i]} * ${bs[i]}`);
    343    }
    344 }
    345 
    346 
    347 // Check relaxed dot product results.
    348 var ins = wasmValidateAndEval(moduleWithSections([
    349    sigSection([v2vSig]),
    350    declSection([0]),
    351    memorySection(1),
    352    exportSection([{funcIndex: 0, name: "dot_i8x16_i7x16_s"},
    353                    {memIndex: 0, name: "mem"}]),
    354    bodySection([
    355        funcBody({locals:[],
    356                    body: [...V128StoreExpr(0, [...V128Load(16),
    357                                                ...V128Load(32),
    358                                                SimdPrefix, ...varU32(I16x8RelaxedDotI8x16I7x16SCode)])]})])]));
    359 var mem8 = new Int8Array(ins.exports.mem.buffer);
    360 var mem16 = new Int16Array(ins.exports.mem.buffer);
    361 var test7bit = [1, 2, 3, 4, 5, 64, 65, 127, 127, 0, 0,
    362                1, 65, 64, 2, 3, 0, 0, 127, 127, 5, 4];
    363 var testNeg = test7bit.concat(test7bit.map(i => ~i));
    364 for (let ai = 0; ai < testNeg.length - 15; ai++)
    365    for (let bi = 0; bi < test7bit.length - 15; bi++) {
    366        set(mem8, 16, testNeg.slice(ai, ai + 16));
    367        set(mem8, 32, test7bit.slice(bi, bi + 16));
    368        ins.exports.dot_i8x16_i7x16_s();
    369        const result = get(mem16, 0, 8);
    370        for (let i = 0; i < 8; i++) {
    371            const expected = ((testNeg[ai + i * 2] * test7bit[bi + i * 2]) +
    372                            (testNeg[ai + i * 2 + 1] * test7bit[bi + i * 2 + 1])) | 0;
    373            assertEq(expected, result[i]);
    374        }
    375    }
    376 
    377 var ins = wasmValidateAndEval(moduleWithSections([
    378    sigSection([v2vSig]),
    379    declSection([0]),
    380    memorySection(1),
    381    exportSection([{funcIndex: 0, name: "dot_i8x16_i7x16_add_s"},
    382                    {memIndex: 0, name: "mem"}]),
    383    bodySection([
    384        funcBody({locals:[],
    385                    body: [...V128StoreExpr(0, [...V128Load(16),
    386                                                ...V128Load(32),
    387                                                ...V128Load(48),
    388                                                SimdPrefix, ...varU32(I32x4RelaxedDotI8x16I7x16AddSCode)])]})])]));
    389 var mem8 = new Int8Array(ins.exports.mem.buffer);
    390 var mem32 = new Int32Array(ins.exports.mem.buffer);
    391 var test7bit = [1, 2, 3, 4, 5, 64, 65, 127, 127, 0, 0,
    392                1, 65, 64, 2, 3, 0, 0, 127, 127, 5, 4];
    393 var testNeg = test7bit.concat(test7bit.map(i => ~i));
    394 var testAcc = [0, 12, 65336, -1, 0x10000000, -0xffffff];
    395 for (let ai = 0; ai < testNeg.length - 15; ai++)
    396    for (let bi = 0; bi < test7bit.length - 15; bi++)
    397        for (let ci = 0; ci < testAcc.length - 3; ci++) {
    398            set(mem8, 16, testNeg.slice(ai, ai + 16));
    399            set(mem8, 32, test7bit.slice(bi, bi + 16));
    400            set(mem32, 48/4, testAcc.slice(ci, ci + 4));
    401            ins.exports.dot_i8x16_i7x16_add_s();
    402            const result = get(mem32, 0, 4);
    403            for (let i = 0; i < 4; i++) {
    404                const a1 = (testNeg[ai + i * 4] * test7bit[bi + i * 4]) +
    405                           (testNeg[ai + i * 4 + 1] * test7bit[bi + i * 4 + 1]);
    406                const a2 = (testNeg[ai + i * 4 + 2] * test7bit[bi + i * 4 + 2]) +
    407                           (testNeg[ai + i * 4 + 3] * test7bit[bi + i * 4 + 3]);
    408                const expected = (testAcc[ci + i] + a1 + a2) | 0;
    409                assertEq(expected, result[i]);
    410            }
    411        }