| /* |
| vim: set ts=8 sts=2 et sw=2 tw=79: |
| Copyright (C) 2013 |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| |
| // A conforming SIMD.js implementation may contain the following deviations to |
| // normal JS numeric behavior: |
| // - Subnormal numbers may or may not be flushed to zero on input or output of |
| // any SIMD operation. |
| |
| // Many of the operations in SIMD.js have semantics which correspond to scalar |
| // operations in JS, however there are a few differences: |
| // - Vector shifts don't mask the shift count. |
| // - Conversions from float to int32 throw on error. |
| // - Load and store operations throw when out of bounds. |
| |
| (function(global) { |
| |
| if (typeof global.SIMD === "undefined") { |
| // SIMD module. |
| global.SIMD = {}; |
| } |
| |
| if (typeof module !== "undefined") { |
| // For CommonJS modules |
| module.exports = global.SIMD; |
| } |
| |
| var SIMD = global.SIMD; |
| |
| // Buffers for bit casting and coercing lane values to those representable in |
| // the underlying lane type. |
| var _f32x4 = new Float32Array(4); |
| var _f64x2 = new Float64Array(_f32x4.buffer); |
| var _i32x4 = new Int32Array(_f32x4.buffer); |
| var _i16x8 = new Int16Array(_f32x4.buffer); |
| var _i8x16 = new Int8Array(_f32x4.buffer); |
| var _ui32x4 = new Uint32Array(_f32x4.buffer); |
| var _ui16x8 = new Uint16Array(_f32x4.buffer); |
| var _ui8x16 = new Uint8Array(_f32x4.buffer); |
| |
| function convertValue(buffer, value) { |
| buffer[0] = value; |
| return buffer[0]; |
| } |
| |
| function convertArray(buffer, array) { |
| for (var i = 0; i < array.length; i++) |
| array[i] = convertValue(buffer, array[i]); |
| return array; |
| } |
| |
| // Utility functions. |
| |
| function isInt32(o) { |
| return (o | 0) === o; |
| } |
| |
| function isTypedArray(o) { |
| return (o instanceof Int8Array) || |
| (o instanceof Uint8Array) || |
| (o instanceof Uint8ClampedArray) || |
| (o instanceof Int16Array) || |
| (o instanceof Uint16Array) || |
| (o instanceof Int32Array) || |
| (o instanceof Uint32Array) || |
| (o instanceof Float32Array) || |
| (o instanceof Float64Array); |
| } |
| |
| function minNum(x, y) { |
| return x != x ? y : |
| y != y ? x : |
| Math.min(x, y); |
| } |
| |
| function maxNum(x, y) { |
| return x != x ? y : |
| y != y ? x : |
| Math.max(x, y); |
| } |
| |
| function clamp(a, min, max) { |
| if (a < min) |
| return min; |
| if (a > max) |
| return max; |
| return a; |
| } |
| |
| // SIMD implementation functions |
| |
| function simdCheckLaneIndex(index, lanes) { |
| if (!isInt32(index)) |
| throw new TypeError('Lane index must be an int32'); |
| if (index < 0 || index >= lanes) |
| throw new RangeError('Lane index must be in bounds'); |
| } |
| |
| // Global lanes array for constructing SIMD values. |
| var lanes = []; |
| |
| function simdCreate(type) { |
| return type.fn.apply(type.fn, lanes); |
| } |
| |
| function simdToString(type, a) { |
| a = type.fn.check(a); |
| var str = "SIMD." + type.name + "("; |
| str += type.fn.extractLane(a, 0); |
| for (var i = 1; i < type.lanes; i++) { |
| str += ", " + type.fn.extractLane(a, i); |
| } |
| return str + ")"; |
| } |
| |
| function simdToLocaleString(type, a) { |
| a = type.fn.check(a); |
| var str = "SIMD." + type.name + "("; |
| str += type.fn.extractLane(a, 0).toLocaleString(); |
| for (var i = 1; i < type.lanes; i++) { |
| str += ", " + type.fn.extractLane(a, i).toLocaleString(); |
| } |
| return str + ")"; |
| } |
| |
| function simdSplat(type, s) { |
| for (var i = 0; i < type.lanes; i++) |
| lanes[i] = s; |
| return simdCreate(type); |
| } |
| |
| function simdReplaceLane(type, a, i, s) { |
| a = type.fn.check(a); |
| simdCheckLaneIndex(i, type.lanes); |
| for (var j = 0; j < type.lanes; j++) |
| lanes[j] = type.fn.extractLane(a, j); |
| lanes[i] = s; |
| return simdCreate(type); |
| } |
| |
| function simdFrom(toType, fromType, a) { |
| a = fromType.fn.check(a); |
| for (var i = 0; i < fromType.lanes; i++) { |
| var v = fromType.fn.extractLane(a, i); |
| if (toType.minVal !== undefined && |
| (v < toType.minVal || v > toType.maxVal)) { |
| throw new RangeError("Can't convert value"); |
| } |
| lanes[i] = v; |
| } |
| return simdCreate(toType); |
| } |
| |
| function simdFromBits(toType, fromType, a) { |
| a = fromType.fn.check(a); |
| for (var i = 0; i < fromType.lanes; i++) |
| fromType.buffer[i] = fromType.fn.extractLane(a, i); |
| for (var i = 0; i < toType.lanes; i++) |
| lanes[i] = toType.buffer[i]; |
| return simdCreate(toType); |
| } |
| |
| function simdSelect(type, selector, a, b) { |
| selector = type.boolType.fn.check(selector); |
| a = type.fn.check(a); |
| b = type.fn.check(b); |
| for (var i = 0; i < type.lanes; i++) { |
| lanes[i] = type.boolType.fn.extractLane(selector, i) ? |
| type.fn.extractLane(a, i) : type.fn.extractLane(b, i); |
| } |
| return simdCreate(type); |
| } |
| |
| function simdSwizzle(type, a, indices) { |
| a = type.fn.check(a); |
| for (var i = 0; i < indices.length; i++) { |
| simdCheckLaneIndex(indices[i], type.lanes); |
| lanes[i] = type.fn.extractLane(a, indices[i]); |
| } |
| return simdCreate(type); |
| } |
| |
| function simdShuffle(type, a, b, indices) { |
| a = type.fn.check(a); |
| b = type.fn.check(b); |
| for (var i = 0; i < indices.length; i++) { |
| simdCheckLaneIndex(indices[i], 2 * type.lanes); |
| lanes[i] = indices[i] < type.lanes ? |
| type.fn.extractLane(a, indices[i]) : |
| type.fn.extractLane(b, indices[i] - type.lanes); |
| } |
| return simdCreate(type); |
| } |
| |
| function unaryNeg(a) { return -a; } |
| function unaryBitwiseNot(a) { return ~a; } |
| function unaryLogicalNot(a) { return !a; } |
| |
| function simdUnaryOp(type, op, a) { |
| a = type.fn.check(a); |
| for (var i = 0; i < type.lanes; i++) |
| lanes[i] = op(type.fn.extractLane(a, i)); |
| return simdCreate(type); |
| } |
| |
| function binaryAnd(a, b) { return a & b; } |
| function binaryOr(a, b) { return a | b; } |
| function binaryXor(a, b) { return a ^ b; } |
| function binaryAdd(a, b) { return a + b; } |
| function binarySub(a, b) { return a - b; } |
| function binaryMul(a, b) { return a * b; } |
| function binaryDiv(a, b) { return a / b; } |
| |
| var binaryImul; |
| if (typeof Math.imul !== 'undefined') { |
| binaryImul = Math.imul; |
| } else { |
| binaryImul = function(a, b) { |
| var ah = (a >>> 16) & 0xffff; |
| var al = a & 0xffff; |
| var bh = (b >>> 16) & 0xffff; |
| var bl = b & 0xffff; |
| // the shift by 0 fixes the sign on the high part |
| // the final |0 converts the unsigned value into a signed value |
| return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); |
| }; |
| } |
| |
| function simdBinaryOp(type, op, a, b) { |
| a = type.fn.check(a); |
| b = type.fn.check(b); |
| for (var i = 0; i < type.lanes; i++) |
| lanes[i] = op(type.fn.extractLane(a, i), type.fn.extractLane(b, i)); |
| return simdCreate(type); |
| } |
| |
| function simdWideningBinaryOp(type, op, a, b) { |
| a = type.fn.check(a); |
| b = type.fn.check(b); |
| for (var i = 0; i < type.wideType.lanes; i++) |
| lanes[i] = op(type.fn.extractLane(a, i), |
| type.fn.extractLane(b, i)); |
| return simdCreate(type.wideType); |
| } |
| |
| function binaryEqual(a, b) { return a == b; } |
| function binaryNotEqual(a, b) { return a != b; } |
| function binaryLess(a, b) { return a < b; } |
| function binaryLessEqual(a, b) { return a <= b; } |
| function binaryGreater(a, b) { return a > b; } |
| function binaryGreaterEqual(a, b) { return a >= b; } |
| |
| function simdRelationalOp(type, op, a, b) { |
| a = type.fn.check(a); |
| b = type.fn.check(b); |
| for (var i = 0; i < type.lanes; i++) |
| lanes[i] = op(type.fn.extractLane(a, i), type.fn.extractLane(b, i)); |
| return simdCreate(type.boolType); |
| } |
| |
| function simdAnyTrue(type, a) { |
| a = type.fn.check(a); |
| for (var i = 0; i < type.lanes; i++) |
| if (type.fn.extractLane(a, i)) return true; |
| return false; |
| } |
| |
| function simdAllTrue(type, a) { |
| a = type.fn.check(a); |
| for (var i = 0; i < type.lanes; i++) |
| if (!type.fn.extractLane(a, i)) return false; |
| return true; |
| } |
| |
| function binaryShiftLeft(a, bits) { return a << bits; } |
| function binaryShiftRightArithmetic(a, bits) { return a >> bits; } |
| function binaryShiftRightLogical(a, bits) { return a >>> bits; } |
| |
| function simdShiftOp(type, op, a, bits) { |
| a = type.fn.check(a); |
| for (var i = 0; i < type.lanes; i++) |
| lanes[i] = op(type.fn.extractLane(a, i), bits); |
| return simdCreate(type); |
| } |
| |
| function simdLoad(type, tarray, index, count) { |
| if (!isTypedArray(tarray)) |
| throw new TypeError("The 1st argument must be a typed array."); |
| if (!isInt32(index)) |
| throw new TypeError("The 2nd argument must be an Int32."); |
| var bpe = tarray.BYTES_PER_ELEMENT; |
| var bytes = count * type.laneSize; |
| if (index < 0 || (index * bpe + bytes) > tarray.byteLength) |
| throw new RangeError("The value of index is invalid."); |
| |
| var buf = type.buffer; |
| var array = bpe == 1 ? _i8x16 : |
| bpe == 2 ? _i16x8 : |
| bpe == 4 ? (tarray instanceof Float32Array ? _f32x4 : _i32x4) : |
| _f64x2; |
| var n = bytes / bpe; |
| for (var i = 0; i < n; i++) |
| array[i] = tarray[index + i]; |
| for (i = 0; i < count; i++) lanes[i] = buf[i]; |
| for (; i < type.lanes; i++) lanes[i] = 0; |
| return simdCreate(type); |
| } |
| |
| function simdStore(type, tarray, index, a, count) { |
| if (!isTypedArray(tarray)) |
| throw new TypeError("The 1st argument must be a typed array."); |
| if (!isInt32(index)) |
| throw new TypeError("The 2nd argument must be an Int32."); |
| var bpe = tarray.BYTES_PER_ELEMENT; |
| var bytes = count * type.laneSize; |
| if (index < 0 || (index * bpe + bytes) > tarray.byteLength) |
| throw new RangeError("The value of index is invalid."); |
| |
| a = type.fn.check(a); |
| // If count is odd and tarray's elements are 8 bytes wide, we have to create |
| // a new view. |
| if ((count % 2 != 0) && bpe == 8) { |
| var view = new type.view(tarray.buffer, |
| tarray.byteOffset + index * 8, count); |
| for (var i = 0; i < count; i++) |
| view[i] = type.fn.extractLane(a, i); |
| } else { |
| for (var i = 0; i < count; i++) |
| type.buffer[i] = type.fn.extractLane(a, i); |
| var array = bpe == 1 ? _i8x16 : |
| bpe == 2 ? _i16x8 : |
| bpe == 4 ? (tarray instanceof Float32Array ? _f32x4 : _i32x4) : |
| _f64x2; |
| var n = bytes / bpe; |
| for (var i = 0; i < n; i++) |
| tarray[index + i] = array[i]; |
| } |
| return a; |
| } |
| |
| // Constructors and extractLane functions are closely related and must be |
| // polyfilled together. |
| |
| // Float32x4 |
| if (typeof SIMD.Float32x4 === "undefined" || |
| typeof SIMD.Float32x4.extractLane === "undefined") { |
| SIMD.Float32x4 = function(s0, s1, s2, s3) { |
| if (!(this instanceof SIMD.Float32x4)) { |
| return new SIMD.Float32x4(s0, s1, s2, s3); |
| } |
| this.s_ = convertArray(_f32x4, [s0, s1, s2, s3]); |
| } |
| |
| SIMD.Float32x4.extractLane = function(v, i) { |
| v = SIMD.Float32x4.check(v); |
| simdCheckLaneIndex(i, 4); |
| return v.s_[i]; |
| } |
| } |
| |
| // Miscellaneous functions that aren't easily parameterized on type. |
| |
| if (typeof SIMD.Float32x4.swizzle === "undefined") { |
| SIMD.Float32x4.swizzle = function(a, s0, s1, s2, s3) { |
| return simdSwizzle(float32x4, a, [s0, s1, s2, s3]); |
| } |
| } |
| |
| if (typeof SIMD.Float32x4.shuffle === "undefined") { |
| SIMD.Float32x4.shuffle = function(a, b, s0, s1, s2, s3) { |
| return simdShuffle(float32x4, a, b, [s0, s1, s2, s3]); |
| } |
| } |
| |
| // Int32x4 |
| if (typeof SIMD.Int32x4 === "undefined" || |
| typeof SIMD.Int32x4.extractLane === "undefined") { |
| SIMD.Int32x4 = function(s0, s1, s2, s3) { |
| if (!(this instanceof SIMD.Int32x4)) { |
| return new SIMD.Int32x4(s0, s1, s2, s3); |
| } |
| this.s_ = convertArray(_i32x4, [s0, s1, s2, s3]); |
| } |
| |
| SIMD.Int32x4.extractLane = function(v, i) { |
| v = SIMD.Int32x4.check(v); |
| simdCheckLaneIndex(i, 4); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Int32x4.swizzle === "undefined") { |
| SIMD.Int32x4.swizzle = function(a, s0, s1, s2, s3) { |
| return simdSwizzle(int32x4, a, [s0, s1, s2, s3]); |
| } |
| } |
| |
| if (typeof SIMD.Int32x4.shuffle === "undefined") { |
| SIMD.Int32x4.shuffle = function(a, b, s0, s1, s2, s3) { |
| return simdShuffle(int32x4, a, b, [s0, s1, s2, s3]); |
| } |
| } |
| |
| // Int16x8 |
| if (typeof SIMD.Int16x8 === "undefined" || |
| typeof SIMD.Int16x8.extractLane === "undefined") { |
| SIMD.Int16x8 = function(s0, s1, s2, s3, s4, s5, s6, s7) { |
| if (!(this instanceof SIMD.Int16x8)) { |
| return new SIMD.Int16x8(s0, s1, s2, s3, s4, s5, s6, s7); |
| } |
| this.s_ = convertArray(_i16x8, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| |
| SIMD.Int16x8.extractLane = function(v, i) { |
| v = SIMD.Int16x8.check(v); |
| simdCheckLaneIndex(i, 8); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Int16x8.swizzle === "undefined") { |
| SIMD.Int16x8.swizzle = function(a, s0, s1, s2, s3, s4, s5, s6, s7) { |
| return simdSwizzle(int16x8, a, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| } |
| |
| if (typeof SIMD.Int16x8.shuffle === "undefined") { |
| SIMD.Int16x8.shuffle = function(a, b, s0, s1, s2, s3, s4, s5, s6, s7) { |
| return simdShuffle(int16x8, a, b, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| } |
| |
| // Int8x16 |
| if (typeof SIMD.Int8x16 === "undefined" || |
| typeof SIMD.Int8x16.extractLane === "undefined") { |
| SIMD.Int8x16 = function(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| if (!(this instanceof SIMD.Int8x16)) { |
| return new SIMD.Int8x16(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15); |
| } |
| this.s_ = convertArray(_i8x16, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| |
| SIMD.Int8x16.extractLane = function(v, i) { |
| v = SIMD.Int8x16.check(v); |
| simdCheckLaneIndex(i, 16); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Int8x16.swizzle === "undefined") { |
| SIMD.Int8x16.swizzle = function(a, s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| return simdSwizzle(int8x16, a, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| } |
| |
| if (typeof SIMD.Int8x16.shuffle === "undefined") { |
| SIMD.Int8x16.shuffle = function(a, b, s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| return simdShuffle(int8x16, a, b, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| } |
| |
| // Uint32x4 |
| if (typeof SIMD.Uint32x4 === "undefined" || |
| typeof SIMD.Uint32x4.extractLane === "undefined") { |
| SIMD.Uint32x4 = function(s0, s1, s2, s3) { |
| if (!(this instanceof SIMD.Uint32x4)) { |
| return new SIMD.Uint32x4(s0, s1, s2, s3); |
| } |
| this.s_ = convertArray(_ui32x4, [s0, s1, s2, s3]); |
| } |
| |
| SIMD.Uint32x4.extractLane = function(v, i) { |
| v = SIMD.Uint32x4.check(v); |
| simdCheckLaneIndex(i, 4); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Uint32x4.swizzle === "undefined") { |
| SIMD.Uint32x4.swizzle = function(a, s0, s1, s2, s3) { |
| return simdSwizzle(uint32x4, a, [s0, s1, s2, s3]); |
| } |
| } |
| |
| if (typeof SIMD.Uint32x4.shuffle === "undefined") { |
| SIMD.Uint32x4.shuffle = function(a, b, s0, s1, s2, s3) { |
| return simdShuffle(uint32x4, a, b, [s0, s1, s2, s3]); |
| } |
| } |
| |
| // Uint16x8 |
| if (typeof SIMD.Uint16x8 === "undefined" || |
| typeof SIMD.Uint16x8.extractLane === "undefined") { |
| SIMD.Uint16x8 = function(s0, s1, s2, s3, s4, s5, s6, s7) { |
| if (!(this instanceof SIMD.Uint16x8)) { |
| return new SIMD.Uint16x8(s0, s1, s2, s3, s4, s5, s6, s7); |
| } |
| this.s_ = convertArray(_ui16x8, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| |
| SIMD.Uint16x8.extractLane = function(v, i) { |
| v = SIMD.Uint16x8.check(v); |
| simdCheckLaneIndex(i, 8); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Uint16x8.swizzle === "undefined") { |
| SIMD.Uint16x8.swizzle = function(a, s0, s1, s2, s3, s4, s5, s6, s7) { |
| return simdSwizzle(uint16x8, a, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| } |
| |
| if (typeof SIMD.Uint16x8.shuffle === "undefined") { |
| SIMD.Uint16x8.shuffle = function(a, b, s0, s1, s2, s3, s4, s5, s6, s7) { |
| return simdShuffle(uint16x8, a, b, [s0, s1, s2, s3, s4, s5, s6, s7]); |
| } |
| } |
| |
| // Uint8x16 |
| if (typeof SIMD.Uint8x16 === "undefined" || |
| typeof SIMD.Uint8x16.extractLane === "undefined") { |
| SIMD.Uint8x16 = function(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| if (!(this instanceof SIMD.Uint8x16)) { |
| return new SIMD.Uint8x16(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15); |
| } |
| this.s_ = convertArray(_ui8x16, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| |
| SIMD.Uint8x16.extractLane = function(v, i) { |
| v = SIMD.Uint8x16.check(v); |
| simdCheckLaneIndex(i, 16); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Uint8x16.swizzle === "undefined") { |
| SIMD.Uint8x16.swizzle = function(a, s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| return simdSwizzle(uint8x16, a, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| } |
| |
| if (typeof SIMD.Uint8x16.shuffle === "undefined") { |
| SIMD.Uint8x16.shuffle = function(a, b, s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| return simdShuffle(uint8x16, a, b, [s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15]); |
| } |
| } |
| |
| // Bool32x4 |
| if (typeof SIMD.Bool32x4 === "undefined" || |
| typeof SIMD.Bool32x4.extractLane === "undefined") { |
| SIMD.Bool32x4 = function(s0, s1, s2, s3) { |
| if (!(this instanceof SIMD.Bool32x4)) { |
| return new SIMD.Bool32x4(s0, s1, s2, s3); |
| } |
| this.s_ = [!!s0, !!s1, !!s2, !!s3]; |
| } |
| |
| SIMD.Bool32x4.extractLane = function(v, i) { |
| v = SIMD.Bool32x4.check(v); |
| simdCheckLaneIndex(i, 4); |
| return v.s_[i]; |
| } |
| } |
| |
| // Bool16x8 |
| if (typeof SIMD.Bool16x8 === "undefined" || |
| typeof SIMD.Bool16x8.extractLane === "undefined") { |
| SIMD.Bool16x8 = function(s0, s1, s2, s3, s4, s5, s6, s7) { |
| if (!(this instanceof SIMD.Bool16x8)) { |
| return new SIMD.Bool16x8(s0, s1, s2, s3, s4, s5, s6, s7); |
| } |
| this.s_ = [!!s0, !!s1, !!s2, !!s3, !!s4, !!s5, !!s6, !!s7]; |
| } |
| |
| SIMD.Bool16x8.extractLane = function(v, i) { |
| v = SIMD.Bool16x8.check(v); |
| simdCheckLaneIndex(i, 8); |
| return v.s_[i]; |
| } |
| } |
| |
| // Bool8x16 |
| if (typeof SIMD.Bool8x16 === "undefined" || |
| typeof SIMD.Bool8x16.extractLane === "undefined") { |
| SIMD.Bool8x16 = function(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15) { |
| if (!(this instanceof SIMD.Bool8x16)) { |
| return new SIMD.Bool8x16(s0, s1, s2, s3, s4, s5, s6, s7, |
| s8, s9, s10, s11, s12, s13, s14, s15); |
| } |
| this.s_ = [!!s0, !!s1, !!s2, !!s3, !!s4, !!s5, !!s6, !!s7, |
| !!s8, !!s9, !!s10, !!s11, !!s12, !!s13, !!s14, !!s15]; |
| } |
| |
| SIMD.Bool8x16.extractLane = function(v, i) { |
| v = SIMD.Bool8x16.check(v); |
| simdCheckLaneIndex(i, 16); |
| return v.s_[i]; |
| } |
| } |
| |
| // Type data to generate the remaining functions. |
| |
| var float32x4 = { |
| name: "Float32x4", |
| fn: SIMD.Float32x4, |
| lanes: 4, |
| laneSize: 4, |
| buffer: _f32x4, |
| view: Float32Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "add", "sub", "mul", "div", "neg", "abs", "min", "max", "minNum", "maxNum", |
| "reciprocalApproximation", "reciprocalSqrtApproximation", "sqrt", |
| "load", "load1", "load2", "load3", "store", "store1", "store2", "store3"], |
| } |
| |
| var int32x4 = { |
| name: "Int32x4", |
| fn: SIMD.Int32x4, |
| lanes: 4, |
| laneSize: 4, |
| minVal: -0x80000000, |
| maxVal: 0x7FFFFFFF, |
| buffer: _i32x4, |
| notFn: unaryBitwiseNot, |
| view: Int32Array, |
| mulFn: binaryImul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "neg", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "load", "load1", "load2", "load3", "store", "store1", "store2", "store3"], |
| } |
| |
| var int16x8 = { |
| name: "Int16x8", |
| fn: SIMD.Int16x8, |
| lanes: 8, |
| laneSize: 2, |
| minVal: -0x8000, |
| maxVal: 0x7FFF, |
| buffer: _i16x8, |
| notFn: unaryBitwiseNot, |
| view: Int16Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "neg", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "addSaturate", "subSaturate", |
| "load", "store"], |
| } |
| |
| var int8x16 = { |
| name: "Int8x16", |
| fn: SIMD.Int8x16, |
| lanes: 16, |
| laneSize: 1, |
| minVal: -0x80, |
| maxVal: 0x7F, |
| buffer: _i8x16, |
| notFn: unaryBitwiseNot, |
| view: Int8Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "neg", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "addSaturate", "subSaturate", |
| "load", "store"], |
| } |
| |
| var uint32x4 = { |
| name: "Uint32x4", |
| fn: SIMD.Uint32x4, |
| lanes: 4, |
| laneSize: 4, |
| minVal: 0, |
| maxVal: 0xFFFFFFFF, |
| unsigned: true, |
| buffer: _ui32x4, |
| notFn: unaryBitwiseNot, |
| view: Uint32Array, |
| mulFn: binaryImul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "load", "load1", "load2", "load3", "store", "store1", "store2", "store3"], |
| } |
| |
| var uint16x8 = { |
| name: "Uint16x8", |
| fn: SIMD.Uint16x8, |
| lanes: 8, |
| laneSize: 2, |
| unsigned: true, |
| minVal: 0, |
| maxVal: 0xFFFF, |
| buffer: _ui16x8, |
| notFn: unaryBitwiseNot, |
| view: Uint16Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "addSaturate", "subSaturate", |
| "load", "store"], |
| } |
| |
| var uint8x16 = { |
| name: "Uint8x16", |
| fn: SIMD.Uint8x16, |
| lanes: 16, |
| laneSize: 1, |
| unsigned: true, |
| minVal: 0, |
| maxVal: 0xFF, |
| buffer: _ui8x16, |
| notFn: unaryBitwiseNot, |
| view: Uint8Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "and", "or", "xor", "not", |
| "add", "sub", "mul", "min", "max", |
| "shiftLeftByScalar", "shiftRightByScalar", |
| "addSaturate", "subSaturate", |
| "load", "store"], |
| } |
| |
| var bool32x4 = { |
| name: "Bool32x4", |
| fn: SIMD.Bool32x4, |
| lanes: 4, |
| laneSize: 4, |
| notFn: unaryLogicalNot, |
| fns: ["check", "splat", "replaceLane", |
| "allTrue", "anyTrue", "and", "or", "xor", "not"], |
| } |
| |
| var bool16x8 = { |
| name: "Bool16x8", |
| fn: SIMD.Bool16x8, |
| lanes: 8, |
| laneSize: 2, |
| notFn: unaryLogicalNot, |
| fns: ["check", "splat", "replaceLane", |
| "allTrue", "anyTrue", "and", "or", "xor", "not"], |
| } |
| |
| var bool8x16 = { |
| name: "Bool8x16", |
| fn: SIMD.Bool8x16, |
| lanes: 16, |
| laneSize: 1, |
| notFn: unaryLogicalNot, |
| fns: ["check", "splat", "replaceLane", |
| "allTrue", "anyTrue", "and", "or", "xor", "not"], |
| } |
| |
| // Each SIMD type has a corresponding Boolean SIMD type, which is returned by |
| // relational ops. |
| float32x4.boolType = int32x4.boolType = uint32x4.boolType = bool32x4; |
| int16x8.boolType = uint16x8.boolType = bool16x8; |
| int8x16.boolType = uint8x16.boolType = bool8x16; |
| |
| // SIMD from<type> types. |
| float32x4.from = [int32x4, uint32x4]; |
| int32x4.from = [float32x4, uint32x4]; |
| int16x8.from = [uint16x8]; |
| int8x16.from = [uint8x16]; |
| uint32x4.from = [float32x4, int32x4]; |
| uint16x8.from = [int16x8]; |
| uint8x16.from = [int8x16]; |
| |
| // SIMD from<type>Bits types. |
| float32x4.fromBits = [int32x4, int16x8, int8x16, uint32x4, uint16x8, uint8x16]; |
| int32x4.fromBits = [float32x4, int16x8, int8x16, uint32x4, uint16x8, uint8x16]; |
| int16x8.fromBits = [float32x4, int32x4, int8x16, uint32x4, uint16x8, uint8x16]; |
| int8x16.fromBits = [float32x4, int32x4, int16x8, uint32x4, uint16x8, uint8x16]; |
| uint32x4.fromBits = [float32x4, int32x4, int16x8, int8x16, uint16x8, uint8x16]; |
| uint16x8.fromBits = [float32x4, int32x4, int16x8, int8x16, uint32x4, uint8x16]; |
| uint8x16.fromBits = [float32x4, int32x4, int16x8, int8x16, uint32x4, uint16x8]; |
| |
| // SIMD widening types. |
| uint16x8.wideType = uint32x4; |
| uint8x16.wideType = uint16x8; |
| |
| var simdTypes = [float32x4, |
| int32x4, int16x8, int8x16, |
| uint32x4, uint16x8, uint8x16, |
| bool32x4, bool16x8, bool8x16]; |
| |
| // SIMD Phase2 types. |
| |
| if (typeof simdPhase2 !== 'undefined') { |
| // Float64x2 |
| if (typeof SIMD.Float64x2 === "undefined" || |
| typeof SIMD.Float64x2.extractLane === "undefined") { |
| SIMD.Float64x2 = function(s0, s1) { |
| if (!(this instanceof SIMD.Float64x2)) { |
| return new SIMD.Float64x2(s0, s1); |
| } |
| this.s_ = convertArray(_f64x2, [s0, s1]); |
| } |
| |
| SIMD.Float64x2.extractLane = function(v, i) { |
| v = SIMD.Float64x2.check(v); |
| simdCheckLaneIndex(i, 2); |
| return v.s_[i]; |
| } |
| } |
| |
| if (typeof SIMD.Float64x2.swizzle === "undefined") { |
| SIMD.Float64x2.swizzle = function(a, s0, s1) { |
| return simdSwizzle(float64x2, a, [s0, s1]); |
| } |
| } |
| |
| if (typeof SIMD.Float64x2.shuffle === "undefined") { |
| SIMD.Float64x2.shuffle = function(a, b, s0, s1) { |
| return simdShuffle(float64x2, a, b, [s0, s1]); |
| } |
| } |
| |
| // Bool64x2 |
| if (typeof SIMD.Bool64x2 === "undefined" || |
| typeof SIMD.Bool64x2.extractLane === "undefined") { |
| SIMD.Bool64x2 = function(s0, s1) { |
| if (!(this instanceof SIMD.Bool64x2)) { |
| return new SIMD.Bool64x2(s0, s1); |
| } |
| this.s_ = [!!s0, !!s1]; |
| } |
| |
| SIMD.Bool64x2.extractLane = function(v, i) { |
| v = SIMD.Bool64x2.check(v); |
| simdCheckLaneIndex(i, 2); |
| return v.s_[i]; |
| } |
| } |
| |
| var float64x2 = { |
| name: "Float64x2", |
| fn: SIMD.Float64x2, |
| lanes: 2, |
| laneSize: 8, |
| buffer: _f64x2, |
| view: Float64Array, |
| mulFn: binaryMul, |
| fns: ["check", "splat", "replaceLane", "select", |
| "equal", "notEqual", "lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual", |
| "add", "sub", "mul", "div", "neg", "abs", "min", "max", "minNum", "maxNum", |
| "reciprocalApproximation", "reciprocalSqrtApproximation", "sqrt", |
| "load", "store"], |
| } |
| |
| var bool64x2 = { |
| name: "Bool64x2", |
| fn: SIMD.Bool64x2, |
| lanes: 2, |
| laneSize: 8, |
| notFn: unaryLogicalNot, |
| fns: ["check", "splat", "replaceLane", |
| "allTrue", "anyTrue", "and", "or", "xor", "not"], |
| } |
| |
| float64x2.boolType = bool64x2; |
| |
| float32x4.fromBits.push(float64x2); |
| int32x4.fromBits.push(float64x2); |
| int16x8.fromBits.push(float64x2); |
| int8x16.fromBits.push(float64x2); |
| uint32x4.fromBits.push(float64x2); |
| uint16x8.fromBits.push(float64x2); |
| uint8x16.fromBits.push(float64x2); |
| |
| float64x2.fromBits = [float32x4, int32x4, int16x8, int8x16, |
| uint32x4, uint16x8, uint8x16]; |
| |
| int32x4.fromBits = [float32x4, int16x8, int8x16, uint32x4, uint16x8, uint8x16]; |
| int16x8.fromBits = [float32x4, int32x4, int8x16, uint32x4, uint16x8, uint8x16]; |
| int8x16.fromBits = [float32x4, int32x4, int16x8, uint32x4, uint16x8, uint8x16]; |
| uint32x4.fromBits = [float32x4, int32x4, int16x8, int8x16, uint16x8, uint8x16]; |
| uint16x8.fromBits = [float32x4, int32x4, int16x8, int8x16, uint32x4, uint8x16]; |
| uint8x16.fromBits = [float32x4, int32x4, int16x8, int8x16, uint32x4, uint16x8]; |
| |
| simdTypes.push(float64x2); |
| simdTypes.push(bool64x2); |
| } |
| |
| // SIMD prototype functions. |
| var prototypeFns = { |
| valueOf: |
| function(type) { |
| return function() { |
| throw new TypeError(type.name + " cannot be converted to a number"); |
| } |
| }, |
| |
| toString: |
| function(type) { |
| return function() { |
| return simdToString(type, this); |
| } |
| }, |
| |
| toLocaleString: |
| function(type) { |
| return function() { |
| return simdToLocaleString(type, this); |
| } |
| }, |
| }; |
| |
| // SIMD constructor functions. |
| |
| var simdFns = { |
| check: |
| function(type) { |
| return function(a) { |
| if (!(a instanceof type.fn)) { |
| throw new TypeError("Argument is not a " + type.name + "."); |
| } |
| return a; |
| } |
| }, |
| |
| splat: |
| function(type) { |
| return function(s) { return simdSplat(type, s); } |
| }, |
| |
| replaceLane: |
| function(type) { |
| return function(a, i, s) { return simdReplaceLane(type, a, i, s); } |
| }, |
| |
| allTrue: |
| function(type) { |
| return function(a) { return simdAllTrue(type, a); } |
| }, |
| |
| anyTrue: |
| function(type) { |
| return function(a) { return simdAnyTrue(type, a); } |
| }, |
| |
| and: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binaryAnd, a, b); |
| } |
| }, |
| |
| or: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binaryOr, a, b); |
| } |
| }, |
| |
| xor: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binaryXor, a, b); |
| } |
| }, |
| |
| not: |
| function(type) { |
| return function(a) { |
| return simdUnaryOp(type, type.notFn, a); |
| } |
| }, |
| |
| equal: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryEqual, a, b); |
| } |
| }, |
| |
| notEqual: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryNotEqual, a, b); |
| } |
| }, |
| |
| lessThan: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryLess, a, b); |
| } |
| }, |
| |
| lessThanOrEqual: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryLessEqual, a, b); |
| } |
| }, |
| |
| greaterThan: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryGreater, a, b); |
| } |
| }, |
| |
| greaterThanOrEqual: |
| function(type) { |
| return function(a, b) { |
| return simdRelationalOp(type, binaryGreaterEqual, a, b); |
| } |
| }, |
| |
| add: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binaryAdd, a, b); |
| } |
| }, |
| |
| sub: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binarySub, a, b); |
| } |
| }, |
| |
| mul: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, type.mulFn, a, b); |
| } |
| }, |
| |
| div: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, binaryDiv, a, b); |
| } |
| }, |
| |
| neg: |
| function(type) { |
| return function(a) { |
| return simdUnaryOp(type, unaryNeg, a); |
| } |
| }, |
| |
| abs: |
| function(type) { |
| return function(a) { |
| return simdUnaryOp(type, Math.abs, a); |
| } |
| }, |
| |
| min: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, Math.min, a, b); |
| } |
| }, |
| |
| max: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, Math.max, a, b); |
| } |
| }, |
| |
| minNum: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, minNum, a, b); |
| } |
| }, |
| |
| maxNum: |
| function(type) { |
| return function(a, b) { |
| return simdBinaryOp(type, maxNum, a, b); |
| } |
| }, |
| |
| load: |
| function(type) { |
| return function(tarray, index) { |
| return simdLoad(type, tarray, index, type.lanes); |
| } |
| }, |
| |
| load1: |
| function(type) { |
| return function(tarray, index) { |
| return simdLoad(type, tarray, index, 1); |
| } |
| }, |
| |
| load2: |
| function(type) { |
| return function(tarray, index) { |
| return simdLoad(type, tarray, index, 2); |
| } |
| }, |
| |
| load3: |
| function(type) { |
| return function(tarray, index) { |
| return simdLoad(type, tarray, index, 3); |
| } |
| }, |
| |
| store: |
| function(type) { |
| return function(tarray, index, a) { |
| return simdStore(type, tarray, index, a, type.lanes); |
| } |
| }, |
| |
| store1: |
| function(type) { |
| return function(tarray, index, a) { |
| return simdStore(type, tarray, index, a, 1); |
| } |
| }, |
| |
| store2: |
| function(type) { |
| return function(tarray, index, a) { |
| return simdStore(type, tarray, index, a, 2); |
| } |
| }, |
| |
| store3: |
| function(type) { |
| return function(tarray, index, a) { |
| return simdStore(type, tarray, index, a, 3); |
| } |
| }, |
| |
| select: |
| function(type) { |
| return function(selector, a, b) { |
| return simdSelect(type, selector, a, b); |
| } |
| }, |
| |
| |
| reciprocalApproximation: |
| function(type) { |
| return function(a) { |
| a = type.fn.check(a); |
| return type.fn.div(type.fn.splat(1.0), a); |
| } |
| }, |
| |
| reciprocalSqrtApproximation: |
| function(type) { |
| return function(a) { |
| a = type.fn.check(a); |
| return type.fn.reciprocalApproximation(type.fn.sqrt(a)); |
| } |
| }, |
| |
| sqrt: |
| function(type) { |
| return function(a) { |
| return simdUnaryOp(type, Math.sqrt, a); |
| } |
| }, |
| |
| shiftLeftByScalar: |
| function(type) { |
| return function(a, bits) { |
| if (bits>>>0 >= type.laneSize * 8) |
| return type.fn.splat(0); |
| return simdShiftOp(type, binaryShiftLeft, a, bits); |
| } |
| }, |
| |
| shiftRightByScalar: |
| function(type) { |
| if (type.unsigned) { |
| return function(a, bits) { |
| if (bits>>>0 >= type.laneSize * 8) |
| return type.fn.splat(0); |
| return simdShiftOp(type, binaryShiftRightLogical, a, bits); |
| } |
| } else { |
| return function(a, bits) { |
| if (bits>>>0 >= type.laneSize * 8) |
| bits = type.laneSize * 8 - 1; |
| return simdShiftOp(type, binaryShiftRightArithmetic, a, bits); |
| } |
| } |
| }, |
| |
| addSaturate: |
| function(type) { |
| function addSaturate(a, b) { |
| return clamp(a + b, type.minVal, type.maxVal); |
| } |
| return function(a, b) { return simdBinaryOp(type, addSaturate, a, b); } |
| }, |
| |
| subSaturate: |
| function(type) { |
| function subSaturate(a, b) { |
| return clamp(a - b, type.minVal, type.maxVal); |
| } |
| return function(a, b) { return simdBinaryOp(type, subSaturate, a, b); } |
| }, |
| } |
| |
| // Install functions. |
| |
| simdTypes.forEach(function(type) { |
| // Install each prototype function on each SIMD prototype. |
| var simdFn = type.fn; |
| var proto = simdFn.prototype; |
| for (var name in prototypeFns) { |
| if (!proto.hasOwnProperty(name)) |
| proto[name] = prototypeFns[name](type); |
| } |
| // Install regular functions. |
| type.fns.forEach(function(name) { |
| if (typeof simdFn[name] === "undefined") |
| simdFn[name] = simdFns[name](type); |
| }); |
| // Install 'fromTIMD' functions. |
| if (type.from) { |
| type.from.forEach(function(fromType) { |
| var name = "from" + fromType.name; |
| var toType = type; // pull type into closure. |
| if (typeof type.fn[name] === "undefined") { |
| type.fn[name] = |
| function(a) { return simdFrom(toType, fromType, a); } |
| } |
| }); |
| } |
| // Install 'fromTIMDBits' functions. |
| if (type.fromBits) { |
| type.fromBits.forEach(function(fromType) { |
| var name = "from" + fromType.name + "Bits"; |
| var toType = type; // pull type into closure. |
| if (typeof type.fn[name] === "undefined") { |
| type.fn[name] = |
| function(a) { return simdFromBits(toType, fromType, a); } |
| } |
| }); |
| } |
| }); |
| |
| // If we're in a browser, the global namespace is named 'window'. If we're |
| // in node, it's named 'global'. If we're in a shell, 'this' might work. |
| })(typeof window !== "undefined" |
| ? window |
| : (typeof process === 'object' && |
| typeof require === 'function' && |
| typeof global === 'object') |
| ? global |
| : this); |