Bug 1123777: Have SIMD shifts + splat + with functions apply ToInt32 to their scalar arguments; r=till
authorBenjamin Bouvier <benj@benj.me>
Tue, 03 Feb 2015 20:37:05 +0100
changeset 256633 a9a074f02927f4661d68297b139df2fb77e6b2c0
parent 256632 f7e6d385cdaa50062241f15dce61fda1a8f0ddbd
child 256634 b87c58ef866756086ef843a0cb0beddcaef9b2c0
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1123777
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1123777: Have SIMD shifts + splat + with functions apply ToInt32 to their scalar arguments; r=till
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/tests/ecma_7/SIMD/float32x4with.js
js/src/tests/ecma_7/SIMD/float64x2with.js
js/src/tests/ecma_7/SIMD/int32x4with.js
js/src/tests/ecma_7/SIMD/shifts.js
js/src/tests/ecma_7/SIMD/splat.js
js/src/tests/ecma_7/SIMD/with.js
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -717,37 +717,28 @@ BinaryFunc(JSContext *cx, unsigned argc,
 
 template<typename V, template<typename T> class OpWith>
 static bool
 FuncWith(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename V::Elem Elem;
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() != 2 || !IsVectorObject<V>(args[0]) ||
-        (!args[1].isNumber() && !args[1].isBoolean()))
-    {
+    if (args.length() != 2 || !IsVectorObject<V>(args[0]))
         return ErrorBadArgs(cx);
-    }
 
-    Elem *val = TypedObjectMemory<Elem *>(args[0]);
+    Elem *vec = TypedObjectMemory<Elem *>(args[0]);
     Elem result[V::lanes];
 
-    if (args[1].isNumber()) {
-        Elem withAsNumber;
-        if (!V::toType(cx, args[1], &withAsNumber))
-            return false;
-        for (unsigned i = 0; i < V::lanes; i++)
-            result[i] = OpWith<Elem>::apply(i, withAsNumber, val[i]);
-    } else {
-        MOZ_ASSERT(args[1].isBoolean());
-        bool withAsBool = args[1].toBoolean();
-        for (unsigned i = 0; i < V::lanes; i++)
-            result[i] = OpWith<Elem>::apply(i, withAsBool, val[i]);
-    }
+    Elem value;
+    if (!V::toType(cx, args[1], &value))
+        return false;
+
+    for (unsigned i = 0; i < V::lanes; i++)
+        result[i] = OpWith<Elem>::apply(i, value, vec[i]);
     return StoreResult<V>(cx, args, result);
 }
 
 template<typename V>
 static bool
 Swizzle(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename V::Elem Elem;
@@ -811,17 +802,17 @@ template<typename Op>
 static bool
 Int32x4BinaryScalar(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 2)
         return ErrorBadArgs(cx);
 
     int32_t result[4];
-    if (!IsVectorObject<Int32x4>(args[0]) || !args[1].isNumber())
+    if (!IsVectorObject<Int32x4>(args[0]))
         return ErrorBadArgs(cx);
 
     int32_t *val = TypedObjectMemory<int32_t *>(args[0]);
     int32_t bits;
     if (!ToInt32(cx, args[1], &bits))
         return false;
 
     for (unsigned i = 0; i < 4; i++)
@@ -906,17 +897,17 @@ FuncZero(JSContext *cx, unsigned argc, V
 
 template<typename Vret>
 static bool
 FuncSplat(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename Vret::Elem RetElem;
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() != 1 || !args[0].isNumber())
+    if (args.length() != 1)
         return ErrorBadArgs(cx);
 
     RetElem arg;
     if (!Vret::toType(cx, args[0], &arg))
         return false;
 
     RetElem result[Vret::lanes];
     for (unsigned i = 0; i < Vret::lanes; i++)
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -268,17 +268,20 @@ struct Float32x4 {
 
     static TypeDescr &GetTypeDescr(GlobalObject &global) {
         return global.float32x4TypeDescr().as<TypeDescr>();
     }
     static Elem toType(Elem a) {
         return a;
     }
     static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
-        *out = v.toNumber();
+        double d;
+        if (!ToNumber(cx, v, &d))
+            return false;
+        *out = float(d);
         return true;
     }
     static void setReturn(CallArgs &args, Elem value) {
         args.rval().setDouble(JS::CanonicalizeNaN(value));
     }
 };
 
 struct Float64x2 {
@@ -288,18 +291,17 @@ struct Float64x2 {
 
     static TypeDescr &GetTypeDescr(GlobalObject &global) {
         return global.float64x2TypeDescr().as<TypeDescr>();
     }
     static Elem toType(Elem a) {
         return a;
     }
     static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
-        *out = v.toNumber();
-        return true;
+        return ToNumber(cx, v, out);
     }
     static void setReturn(CallArgs &args, Elem value) {
         args.rval().setDouble(JS::CanonicalizeNaN(value));
     }
 };
 
 struct Int32x4 {
     typedef int32_t Elem;
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/float32x4with.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 946042;
-var float32x4 = SIMD.float32x4;
-var int32x4 = SIMD.int32x4;
-
-var summary = 'float32x4 with';
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  var a = float32x4(1, 2, 3, 4);
-  var x = SIMD.float32x4.withX(a, 5);
-  var y = SIMD.float32x4.withY(a, 5);
-  var z = SIMD.float32x4.withZ(a, 5);
-  var w = SIMD.float32x4.withW(a, 5);
-  assertEq(x.x, 5);
-  assertEq(x.y, 2);
-  assertEq(x.z, 3);
-  assertEq(x.w, 4);
-
-  assertEq(y.x, 1);
-  assertEq(y.y, 5);
-  assertEq(y.z, 3);
-  assertEq(y.w, 4);
-
-  assertEq(z.x, 1);
-  assertEq(z.y, 2);
-  assertEq(z.z, 5);
-  assertEq(z.w, 4);
-
-  assertEq(w.x, 1);
-  assertEq(w.y, 2);
-  assertEq(w.z, 3);
-  assertEq(w.w, 5);
-
-  var b = float32x4(1.87, 2.08, 3.84, 4.17);
-  var x1 = SIMD.float32x4.withX(b, 5.38);
-  var y1 = SIMD.float32x4.withY(b, 5.19);
-  var z1 = SIMD.float32x4.withZ(b, 5.11);
-  var w1 = SIMD.float32x4.withW(b, 5.07);
-  assertEq(x1.x, Math.fround(5.38));
-  assertEq(x1.y, Math.fround(2.08));
-  assertEq(x1.z, Math.fround(3.84));
-  assertEq(x1.w, Math.fround(4.17));
-
-  assertEq(y1.x, Math.fround(1.87));
-  assertEq(y1.y, Math.fround(5.19));
-  assertEq(y1.z, Math.fround(3.84));
-  assertEq(y1.w, Math.fround(4.17));
-
-  assertEq(z1.x, Math.fround(1.87));
-  assertEq(z1.y, Math.fround(2.08));
-  assertEq(z1.z, Math.fround(5.11));
-  assertEq(z1.w, Math.fround(4.17));
-
-  assertEq(w1.x, Math.fround(1.87));
-  assertEq(w1.y, Math.fround(2.08));
-  assertEq(w1.z, Math.fround(3.84));
-  assertEq(w1.w, Math.fround(5.07));
-
-  var c = float32x4(NaN, -0, Infinity, -Infinity);
-  var x2 = SIMD.float32x4.withX(c, 0);
-  var y2 = SIMD.float32x4.withY(c, 0);
-  var z2 = SIMD.float32x4.withZ(c, 0);
-  var w2 = SIMD.float32x4.withW(c, 0);
-  assertEq(x2.x, 0);
-  assertEq(x2.y, -0);
-  assertEq(x2.z, Infinity);
-  assertEq(x2.w, -Infinity);
-
-  assertEq(y2.x, NaN);
-  assertEq(y2.y, 0);
-  assertEq(y2.z, Infinity);
-  assertEq(y2.w, -Infinity);
-
-  assertEq(z2.x, NaN);
-  assertEq(z2.y, -0);
-  assertEq(z2.z, 0);
-  assertEq(z2.w, -Infinity);
-
-  assertEq(w2.x, NaN);
-  assertEq(w2.y, -0);
-  assertEq(w2.z, Infinity);
-  assertEq(w2.w, 0);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/float64x2with.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 1031203;
-var float64x2 = SIMD.float64x2;
-
-var summary = 'float64x2 with';
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * https://creativecommons.org/publicdomain/zero/1.0/
- */
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  var a = float64x2(1, 2);
-  var x = float64x2.withX(a, 5);
-  var y = float64x2.withY(a, 5);
-  assertEq(x.x, 5);
-  assertEq(x.y, 2);
-  assertEq(y.x, 1);
-  assertEq(y.y, 5);
-
-  var b = float64x2(NaN, -0);
-  var x1 = float64x2.withX(b, Infinity);
-  var y1 = float64x2.withY(b, -Infinity);
-  assertEq(x1.x, Infinity);
-  assertEq(x1.y, -0);
-  assertEq(y1.x, NaN);
-  assertEq(y1.y, -Infinity);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/int32x4with.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 946042;
-var float32x4 = SIMD.float32x4;
-var int32x4 = SIMD.int32x4;
-
-var summary = 'int32x4 with';
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  var INT32_MAX = Math.pow(2, 31) - 1;
-
-  var a = int32x4(1, 2, 3, 4);
-  var x = SIMD.int32x4.withX(a, 5);
-  var y = SIMD.int32x4.withY(a, 5);
-  var z = SIMD.int32x4.withZ(a, 5);
-  var w = SIMD.int32x4.withW(a, INT32_MAX + 1);
-  assertEq(x.x, 5);
-  assertEq(y.y, 5);
-  assertEq(z.z, 5);
-  assertEq(w.w, (INT32_MAX + 1) | 0);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
--- a/js/src/tests/ecma_7/SIMD/shifts.js
+++ b/js/src/tests/ecma_7/SIMD/shifts.js
@@ -13,25 +13,39 @@ function lsh(a, b) {
 function rsh(a, b) {
     return (a >> b) | 0;
 }
 function ursh(a, b) {
     return (a >>> b) | 0;
 }
 
 function test() {
+  function TestError() {};
+
+  var good = {valueOf: () => 21};
+  var bad = {valueOf: () => {throw new TestError(); }};
+
   for (var v of [
             int32x4(-1, 2, -3, 4),
             int32x4(INT32_MAX, INT32_MIN, INT32_MAX - 1, INT32_MIN + 1)
        ])
   {
       for (var bits = 0; bits < 32; bits++) {
           testBinaryScalarFunc(v, bits, int32x4.shiftLeftByScalar, lsh);
           testBinaryScalarFunc(v, bits, int32x4.shiftRightArithmeticByScalar, rsh);
           testBinaryScalarFunc(v, bits, int32x4.shiftRightLogicalByScalar, ursh);
       }
+      // Test that the shift count is coerced to an int32.
+      testBinaryScalarFunc(v, undefined, int32x4.shiftLeftByScalar, lsh);
+      testBinaryScalarFunc(v, 3.5, int32x4.shiftLeftByScalar, lsh);
+      testBinaryScalarFunc(v, good, int32x4.shiftLeftByScalar, lsh);
   }
 
+  var v = SIMD.int32x4(1,2,3,4);
+  assertThrowsInstanceOf(() => SIMD.int32x4.shiftLeftByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.int32x4.shiftRightArithmeticByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.int32x4.shiftRightLogicalByScalar(v, bad), TestError);
+
   if (typeof reportCompare === "function")
     reportCompare(true, true);
 }
 
 test();
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/SIMD/splat.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
+
+var float64x2 = SIMD.float64x2;
+var float32x4 = SIMD.float32x4;
+var int32x4 = SIMD.int32x4;
+
+function TestSplatX4(type, inputs, coerceFunc) {
+    for (var x of inputs) {
+        assertEqX4(SIMD[type].splat(x), [x, x, x, x].map(coerceFunc));
+    }
+}
+
+function TestSplatX2(type, inputs, coerceFunc) {
+    for (var x of inputs) {
+        assertEqX2(SIMD[type].splat(x), [x, x].map(coerceFunc));
+    }
+}
+
+function test() {
+    function TestError(){};
+
+    var good = {valueOf: () => 19.89};
+    var bad = {valueOf: () => { throw new TestError(); }};
+
+    TestSplatX4('int32x4', [0, undefined, 3.5, 42, -1337, INT32_MAX, INT32_MAX + 1, good], (x) => x | 0);
+    assertThrowsInstanceOf(() => SIMD.int32x4.splat(bad), TestError);
+
+    TestSplatX4('float32x4', [0, undefined, 3.5, 42, -13.37, Infinity, NaN, -0, good], (x) => Math.fround(x));
+    assertThrowsInstanceOf(() => SIMD.float32x4.splat(bad), TestError);
+
+    TestSplatX2('float64x2', [0, undefined, 3.5, 42, -13.37, Infinity, NaN, -0, good], (x) => +x);
+    assertThrowsInstanceOf(() => SIMD.float64x2.splat(bad), TestError);
+
+    if (typeof reportCompare === "function")
+        reportCompare(true, true);
+}
+
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/SIMD/with.js
@@ -0,0 +1,90 @@
+// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
+var BUGNUMBER = 946042;
+var float32x4 = SIMD.float32x4;
+var int32x4 = SIMD.int32x4;
+var float64x2 = SIMD.float64x2;
+
+var summary = 'with{X,Y,Z,W}';
+
+function withX(arr, x) {
+    if (arr.length == 2)
+        return [x, arr[1]];
+    return [x, arr[1], arr[2], arr[3]];
+}
+function withY(arr, x) {
+    if (arr.length == 2)
+        return [arr[0], x];
+    return [arr[0], x, arr[2], arr[3]];
+}
+function withZ(arr, x) {
+    return [arr[0], arr[1], x, arr[3]];
+}
+function withW(arr, x) {
+    return [arr[0], arr[1], arr[2], x];
+}
+
+function testWith(vec, scalar, simdFunc, func) {
+    var varr = simdToArray(vec);
+    var observed = simdToArray(simdFunc(vec, scalar));
+    var expected = func(varr, scalar);
+    for (var i = 0; i < observed.length; i++)
+        assertEq(observed[i], expected[i]);
+}
+
+function test() {
+  print(BUGNUMBER + ": " + summary);
+
+  function testType(type, inputs) {
+      var length = simdToArray(inputs[0][0]).length;
+      for (var [vec, s] of inputs) {
+          testWith(vec, s, SIMD[type].withX, withX);
+          testWith(vec, s, SIMD[type].withY, withY);
+          if (length <= 2)
+              continue;
+          testWith(vec, s, SIMD[type].withZ, withZ);
+          testWith(vec, s, SIMD[type].withW, withW);
+      }
+  }
+
+  function TestError(){};
+  var good = {valueOf: () => 42};
+  var bad = {valueOf: () => {throw new TestError(); }};
+
+  var float32x4inputs = [
+      [float32x4(1, 2, 3, 4), 5],
+      [float32x4(1.87, 2.08, 3.84, 4.17), Math.fround(13.37)],
+      [float32x4(NaN, -0, Infinity, -Infinity), 0]
+  ];
+  testType('float32x4', float32x4inputs);
+
+  var v = float32x4inputs[1][0];
+  assertEqX4(float32x4.withX(v, good), withX(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => float32x4.withX(v, bad), TestError);
+
+  var float64x2inputs = [
+      [float64x2(1, 2), 5],
+      [float64x2(1.87, 2.08), Math.fround(13.37)],
+      [float64x2(NaN, -0), 0]
+  ];
+  testType('float64x2', float64x2inputs);
+
+  var v = float64x2inputs[1][0];
+  assertEqX4(float64x2.withX(v, good), withX(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => float64x2.withX(v, bad), TestError);
+
+  var int32x4inputs = [
+      [int32x4(1, 2, 3, 4), 5],
+      [int32x4(INT32_MIN, INT32_MAX, 3, 4), INT32_MIN],
+  ];
+  testType('int32x4', int32x4inputs);
+
+  var v = int32x4inputs[1][0];
+  assertEqX4(int32x4.withX(v, good), withX(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => int32x4.withX(v, bad), TestError);
+
+  if (typeof reportCompare === "function")
+    reportCompare(true, true);
+}
+
+test();
+