SIMD(发音/sim-dee/)是“Single Instruction/Multiple Data”的缩写,意为“单指令,多数据”。它是JavaScript操作CPU对应指令的接口,你可以看做这是一种不同的运算执行模式。与它相对的是SISD(“Single Instruction/Single Data”),即“单指令,单数据”。
var a = [1, 2, 3, 4];
var b = [5, 6, 7, 8];
var c = [];
c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
c[3] = a[3] + b[3];
c // Array[6, 8, 10, 12]
上面代码中,数组a和b的对应成员相加,结果放入数组c。它的运算模式是依次处理每个数组成员,一共有四个数组成员,所以需要运算4次。
如果采用SIMD模式,只要运算一次就够了。
var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);
var c = SIMD.Float32x4.add(a, b); // Float32x4[6, 8, 10, 12]
一次SIMD运算,可以处理多个数据,这些数据被称为“通道”(lane)。上面代码中,一次运算了四个数据,因此就是四个通道。
SIMD通常用于矢量运算。
v + w = 〈v1, …, vn〉+ 〈w1, …, wn〉
= 〈v1+w1, …, vn+wn〉
多元矢量的各种运算使用SIMD都会变快。
SIMD提供12种数据类型,总长度都是128个二进制位。
每种数据类型被x符号分隔成两部分,后面的部分表示通道数,前面的部分表示每个通道的宽度和类型。比如,Float32x4就表示这个值有4个通道,每个通道是一个32位浮点数。
每个通道之中,可以放置四种数据:
每种数据类型都有一系列运算符,支持基本的数学运算。
//abs
var a = SIMD.Float32x4(-1, -2, 0, NaN);
SIMD.Float32x4.abs(a)// Float32x4[1, 2, 0, NaN]
//neg
var b = SIMD.Float64x2(NaN, Infinity);
SIMD.Float64x2.neg(b)// Float64x2[NaN, -Infinity]
//add,如果两个值相加发生溢出,溢出的二进制位会被丢弃
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
var b = SIMD.Float32x4(5.0, 10.0, 15.0, 20.0);
var c = SIMD.Float32x4.add(a, b);
// Float32x4[6.0, 12.0, 18.0, 24.0]
//addSaturate,如果两个值相加发生溢出,返回该数据类型的最大值。
var c = SIMD.Int16x8(32765, 32766, 32767, 32767, 1, 1, 1, 1);
var d = SIMD.Int16x8(1, 1, 1, 5000, 1, 1, 1, 1);
SIMD.Int16x8.addSaturate(c, d);
// Int16x8[32766, 32767, 32767, 32767, 2, 2, 2, 2]
//sub,如果两个值相减发生溢出,溢出的二进制位会被丢弃;
var a = SIMD.Uint16x8(5, 1, 1, 1, 1, 1, 1, 1);
var b = SIMD.Uint16x8(10, 1, 1, 1, 1, 1, 1, 1);
SIMD.Uint16x8.subSaturate(a, b)
// Uint16x8[0, 0, 0, 0, 0, 0, 0, 0]
//subSaturate,如果两个值相减发生溢出,返回该数据类型的最小值。
var c = SIMD.Int16x8(-100, 0, 0, 0, 0, 0, 0, 0);
var d = SIMD.Int16x8(32767, 0, 0, 0, 0, 0, 0, 0);
SIMD.Int16x8.subSaturate(c, d)
// Int16x8[-32768, 0, 0, 0, 0, 0, 0, 0, 0]
//mul
var a = SIMD.Float32x4(-1, -2, 3, 4);
var b = SIMD.Float32x4(3, 3, 3, 3);
SIMD.Float32x4.mul(a, b)
// Float32x4[-3, -6, 9, 12]
//div
var a = SIMD.Float32x4(2, 2, 2, 2);
var b = SIMD.Float32x4(4, 4, 4, 4);
SIMD.Float32x4.div(a, b)
// Float32x4[0.5, 0.5, 0.5, 0.5]
//sqrt
var b = SIMD.Float64x2(4, 8);
SIMD.Float64x2.sqrt(b)
// Float64x2[2, 2.8284271247461903]
//reciprocalApproximation(),求出每个通道的倒数(1 / x)
//float only
var a = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.reciprocalApproximation(a);
// Float32x4[1, 0.5, 0.3333333432674408, 0.25]
//reciprocalSqrtApproximation,求出每个通道的平方根的倒数(1 / (x^0.5))
//float only
var a = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.reciprocalSqrtApproximation(a)
// Float32x4[1, 0.7071067690849304, 0.5773502588272095, 0.5]
//shiftLeftByScalar(),将每个通道的值左移指定的位数
//如果左移后,新的值超出了当前数据类型的位数,溢出的部分会被丢弃
//int only
var ix4 = SIMD.Int32x4(1, 2, 3, 4);
var jx4 = SIMD.Int32x4.shiftLeftByScalar(ix4, 32);
// Int32x4[0, 0, 0, 0]
//shiftRightByScalar(),将每个通道的值右移指定的位数
//如果原来通道的值是带符号的值,则符号位保持不变,不受右移影响
//如果是不带符号位的值,则右移后头部会补0。
//int only
var a = SIMD.Int32x4(1, 2, 4, -8);
SIMD.Int32x4.shiftRightByScalar(a, 1);
// Int32x4[0, 1, 2, -4]
SIMD.%type%.check()
SIMD.%type%.extractLane(),SIMD.%type%.replaceLane()
SIMD.%type%.load()
SIMD.%type%.store()
SIMD.%type%.splat()
SIMD.%type%.swizzle()
SIMD.%type%.shuffle()
SIMD.%type%.equal(),SIMD.%type%.notEqual()
SIMD.%type%.greaterThan(),SIMD.%type%.greaterThanOrEqual()
SIMD.%type%.lessThan(),SIMD.%type%.lessThanOrEqual()
SIMD.%type%.select()
SIMD.%BooleanType%.allTrue(),SIMD.%BooleanType%.anyTrue()
SIMD.%type%.min(),SIMD.%type%.minNum()
SIMD.%type%.max(),SIMD.%type%.maxNum()
SIMD.%type%.and()
SIMD.%type%.or()
SIMD.%type%.xor()
SIMD.%type%.not()
SIMD提供以下方法,用来将一种数据类型转为另一种数据类型。
SIMD.%type%.fromFloat32x4()
SIMD.%type%.fromFloat32x4Bits()
SIMD.%type%.fromFloat64x2Bits()
SIMD.%type%.fromInt32x4()
SIMD.%type%.fromInt32x4Bits()
SIMD.%type%.fromInt16x8Bits()
SIMD.%type%.fromInt8x16Bits()
SIMD.%type%.fromUint32x4()
SIMD.%type%.fromUint32x4Bits()
SIMD.%type%.fromUint16x8Bits()
SIMD.%type%.fromUint8x16Bits()
带有Bits后缀的方法,会原封不动地将二进制位拷贝到新的数据类型;不带后缀的方法,则会进行数据类型转换。
SIMD.%type%.prototype.toString()
var a = SIMD.Float32x4(11, 22, 33, 44);
a.toString() // "SIMD.Float32x4(11, 22, 33, 44)"