Bug 1233111 - Remove geometry altering SIMD conversions. r?bbouvier draft
authorJakob Stoklund Olesen <jolesen@mozilla.com>
Wed, 23 Dec 2015 09:52:39 -0800
changeset 317283 ad65052cc8419b17aa12eed380083d2e55fb86d8
parent 317282 acef8183c3f0f6ed25077fbc93380afede732d80
child 317284 b693e4f3ff7f5ec9efcadce492ab51496359eb9d
push id8682
push userjolesen@mozilla.com
push dateWed, 23 Dec 2015 17:52:08 +0000
reviewersbbouvier
bugs1233111
milestone46.0a1
Bug 1233111 - Remove geometry altering SIMD conversions. r?bbouvier In the current SIMD.js spec, value conversions are only defined between types with the same number of lanes: Float32x4.fromInt32x4() Float32x4.fromUInt32x4() Int32x4.fromFloat32x4() UInt32x4.fromFloat32x4() Remove existing conversion operators between vectors with different numbers of lanes: Int32x4.fromFloat64x2() Float32x4.fromFloat64x2() Float64x2.fromInt32x4() Float64x2.fromFloat32x4() Add a static assertion to FuncConvert.
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/tests/ecma_7/SIMD/conversions.js
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -1077,36 +1077,34 @@ struct ThrowOnConvert<float, int32_t> : 
 
 template<typename V, typename Vret>
 static bool
 FuncConvert(JSContext* cx, unsigned argc, Value* vp)
 {
     typedef typename V::Elem Elem;
     typedef typename Vret::Elem RetElem;
 
+    static_assert(V::lanes == Vret::lanes, "Can only convert from same number of lanes");
+
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1 || !IsVectorObject<V>(args[0]))
         return ErrorBadArgs(cx);
 
     Elem* val = TypedObjectMemory<Elem*>(args[0]);
 
     RetElem result[Vret::lanes];
-    for (unsigned i = 0; i < Min(V::lanes, Vret::lanes); i++) {
+    for (unsigned i = 0; i < V::lanes; i++) {
         if (ThrowOnConvert<Elem, RetElem>::value(val[i])) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                                  JSMSG_SIMD_FAILED_CONVERSION);
             return false;
         }
         result[i] = ConvertScalar<RetElem>(val[i]);
     }
 
-    // Fill remaining lanes with 0
-    for (unsigned i = V::lanes; i < Vret::lanes; i++)
-        result[i] = 0;
-
     return StoreResult<Vret>(cx, args, result);
 }
 
 template<typename V, typename Vret>
 static bool
 FuncConvertBits(JSContext* cx, unsigned argc, Value* vp)
 {
     typedef typename Vret::Elem RetElem;
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -102,17 +102,16 @@
 #define BOOL64X2_FUNCTION_LIST(V)                                                     \
   BOOL64X2_UNARY_FUNCTION_LIST(V)                                                     \
   BOOL64X2_BINARY_FUNCTION_LIST(V)                                                    \
   BOOL64X2_TERNARY_FUNCTION_LIST(V)
 
 #define FLOAT32X4_UNARY_FUNCTION_LIST(V)                                              \
   V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1)                                   \
   V(check, (UnaryFunc<Float32x4, Identity, Float32x4>), 1)                            \
-  V(fromFloat64x2, (FuncConvert<Float64x2, Float32x4> ), 1)                           \
   V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1)                    \
   V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float32x4>), 1)                        \
   V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float32x4>), 1)                        \
   V(fromInt32x4, (FuncConvert<Int32x4, Float32x4> ), 1)                               \
   V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1)                        \
   V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1)                                   \
   V(reciprocalApproximation, (UnaryFunc<Float32x4, RecApprox, Float32x4>), 1)         \
   V(reciprocalSqrtApproximation, (UnaryFunc<Float32x4, RecSqrtApprox, Float32x4>), 1) \
@@ -156,21 +155,19 @@
   FLOAT32X4_UNARY_FUNCTION_LIST(V)                                                    \
   FLOAT32X4_BINARY_FUNCTION_LIST(V)                                                   \
   FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                                  \
   FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)
 
 #define FLOAT64X2_UNARY_FUNCTION_LIST(V)                                              \
   V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1)                                   \
   V(check, (UnaryFunc<Float64x2, Identity, Float64x2>), 1)                            \
-  V(fromFloat32x4, (FuncConvert<Float32x4, Float64x2> ), 1)                           \
   V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1)                    \
   V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float64x2>), 1)                        \
   V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float64x2>), 1)                        \
-  V(fromInt32x4, (FuncConvert<Int32x4, Float64x2> ), 1)                               \
   V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float64x2>), 1)                        \
   V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1)                                   \
   V(reciprocalApproximation, (UnaryFunc<Float64x2, RecApprox, Float64x2>), 1)         \
   V(reciprocalSqrtApproximation, (UnaryFunc<Float64x2, RecSqrtApprox, Float64x2>), 1) \
   V(splat, (FuncSplat<Float64x2>), 1)                                                 \
   V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1)
 
 #define FLOAT64X2_BINARY_FUNCTION_LIST(V)                                             \
@@ -295,17 +292,16 @@
   INT16X8_BINARY_FUNCTION_LIST(V)                                                     \
   INT16X8_TERNARY_FUNCTION_LIST(V)                                                    \
   INT16X8_SHUFFLE_FUNCTION_LIST(V)
 
 #define INT32X4_UNARY_FUNCTION_LIST(V)                                                \
   V(check, (UnaryFunc<Int32x4, Identity, Int32x4>), 1)                                \
   V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1)                              \
   V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1)                      \
-  V(fromFloat64x2, (FuncConvert<Float64x2, Int32x4>), 1)                              \
   V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1)                      \
   V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Int32x4>), 1)                          \
   V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Int32x4>), 1)                          \
   V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1)                                       \
   V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1)                                       \
   V(splat, (FuncSplat<Int32x4>), 0)
 
 #define INT32X4_BINARY_FUNCTION_LIST(V)                                               \
--- a/js/src/tests/ecma_7/SIMD/conversions.js
+++ b/js/src/tests/ecma_7/SIMD/conversions.js
@@ -1,75 +1,15 @@
 // |reftest| skip-if(!this.hasOwnProperty("SIMD"))
 var Float32x4 = SIMD.Float32x4;
 var Float64x2 = SIMD.Float64x2;
 var Int8x16 = SIMD.Int8x16;
 var Int16x8 = SIMD.Int16x8;
 var Int32x4 = SIMD.Int32x4;
 
-function testFloat32x4FromFloat64x2() {
-  function expected(v) {
-    return [...(v.map(Math.fround)), 0, 0];
-  }
-
-  var vals = [
-    [1, 2],
-    [-0, NaN],
-    [Infinity, -Infinity],
-    [Math.pow(2, 25) - 1, -Math.pow(25)],
-    [Math.pow(2, 1000), Math.pow(2, -1000)]
-  ];
-
-  for (var v of vals) {
-    assertEqX4(Float32x4.fromFloat64x2(Float64x2(...v)), expected(v));
-  }
-
-  // Test rounding to nearest, break tie with even
-  var f1 = makeFloat(0, 127, 0);
-  assertEq(f1, 1);
-
-  var f2 = makeFloat(0, 127, 1);
-  var d = makeDouble(0, 1023, 0x0000020000000);
-  assertEq(f2, d);
-
-  var mid = makeDouble(0, 1023, 0x0000010000000);
-  assertEq((1 + d) / 2, mid);
-
-  var nextMid = makeDouble(0, 1023, 0x0000010000001);
-
-  // mid is halfway between f1 and f2 => tie to even, which is f1
-  var v = Float64x2(mid, nextMid);
-  assertEqX4(Float32x4.fromFloat64x2(v), [f1, f2, 0, 0]);
-
-  var f3 = makeFloat(0, 127, 2);
-  var d = makeDouble(0, 1023, 0x0000040000000);
-  assertEq(f3, d);
-
-  mid = makeDouble(0, 1023, 0x0000030000000);
-  assertEq((f2 + f3) / 2, mid);
-
-  // same here. tie to even, which is f3 here
-  nextMid = makeDouble(0, 1023, 0x0000030000001);
-  var v = Float64x2(mid, nextMid);
-  assertEqX4(Float32x4.fromFloat64x2(v), [f3, f3, 0, 0]);
-
-  // Test boundaries
-  var biggestFloat = makeFloat(0, 127 + 127, 0x7fffff);
-  assertEq(makeDouble(0, 1023 + 127, 0xfffffe0000000), biggestFloat);
-
-  var lowestFloat = makeFloat(1, 127 + 127, 0x7fffff);
-  assertEq(makeDouble(1, 1023 + 127, 0xfffffe0000000), lowestFloat);
-
-  var v = Float64x2(lowestFloat, biggestFloat);
-  assertEqX4(Float32x4.fromFloat64x2(v), [lowestFloat, biggestFloat, 0, 0]);
-
-  var v = Float64x2(makeDouble(0, 1023 + 127, 0xfffffe0000001), makeDouble(0, 1023 + 127, 0xffffff0000000));
-  assertEqX4(Float32x4.fromFloat64x2(v), [biggestFloat, Infinity, 0, 0]);
-}
-
 function testFloat32x4FromFloat64x2Bits() {
   var valsExp = [
     [[2.000000473111868, 512.0001225471497], [1.0, 2.0, 3.0, 4.0]],
     [[-0, NaN], [0, -0, 0, NaN]],
     [[Infinity, -Infinity], [0, NaN, 0, NaN]]
   ];
 
   for (var [v,w] of valsExp) {
@@ -175,33 +115,16 @@ function testFloat32x4FromInt32x4Bits() 
     [[INT32_MIN, INT32_MAX, 0, 0], [-0, NaN, 0, 0]]
   ];
 
   for (var [v,w] of valsExp) {
     assertEqX4(Float32x4.fromInt32x4Bits(Int32x4(...v)), w);
   }
 }
 
-function testFloat64x2FromFloat32x4() {
-  function expected(v) {
-    return v.slice(0, 2).map(Math.fround);
-  }
-
-  var vals = [
-    [100, 200, 300, 400],
-    [NaN, -0, NaN, -0],
-    [Infinity, -Infinity, Infinity, -Infinity],
-    [13.37, 12.853, 49.97, 53.124]
-  ];
-
-  for (var v of vals) {
-    assertEqX2(Float64x2.fromFloat32x4(Float32x4(...v)), expected(v));
-  }
-}
-
 function testFloat64x2FromFloat32x4Bits() {
   var valsExp = [
     [[0, 1.875, 0, 2], [1.0, 2.0]],
     [[NaN, -0, Infinity, -Infinity], [-1.058925634e-314, -1.404448428688076e+306]]
   ];
 
   for (var [v,w] of valsExp) {
     assertEqX2(Float64x2.fromFloat32x4Bits(Float32x4(...v)), w);
@@ -244,31 +167,16 @@ function testFloat64x2FromInt16x8Bits() 
   for (var v of vals) {
     var f = Int16x8(...v);
     assertEqX2(Float64x2.fromInt16x8Bits(f), expected(f, ArrayBuffer));
     if (typeof SharedArrayBuffer != "undefined")
       assertEqX2(Float64x2.fromInt16x8Bits(f), expected(f, SharedArrayBuffer));
   }
 }
 
-function testFloat64x2FromInt32x4() {
-  function expected(v) {
-    return v.slice(0, 2);
-  }
-
-  var vals = [
-    [1, 2, 3, 4],
-    [INT32_MAX, INT32_MIN, 0, 0]
-  ];
-
-  for (var v of vals) {
-    assertEqX2(Float64x2.fromInt32x4(Int32x4(...v)), expected(v));
-  }
-}
-
 function testFloat64x2FromInt32x4Bits() {
   var valsExp = [
     [[0x00000000, 0x3ff00000, 0x0000000, 0x40000000], [1.0, 2.0]],
     [[0xabcdef12, 0x3ff00000, 0x21fedcba, 0x40000000], [1.0000006400213732, 2.0000002532866263]]
   ];
 
   for (var [v,w] of valsExp) {
     assertEqX2(Float64x2.fromInt32x4Bits(Int32x4(...v)), w);
@@ -313,52 +221,16 @@ function testInt32x4FromFloat32x4Bits() 
     [[NaN, -0, Infinity, -Infinity], [0x7fc00000 | 0, 0x80000000 | 0, 0x7f800000 | 0, 0xff800000 | 0]]
   ];
 
   for (var [v,w] of valsExp) {
     assertEqX4(Int32x4.fromFloat32x4Bits(Float32x4(...v)), w);
   }
 }
 
-function testInt32x4FromFloat64x2() {
-  assertEqX4(Int32x4.fromFloat64x2(Float64x2(1, 2.2)), [1, 2, 0, 0]);
-
-  var g = Float64x2(Infinity, 0);
-  assertThrowsInstanceOf(() => Int32x4.fromFloat64x2(g), RangeError);
-
-  var g = Float64x2(-Infinity, 0);
-  assertThrowsInstanceOf(() => Int32x4.fromFloat64x2(g), RangeError);
-
-  var g = Float64x2(NaN, 0);
-  assertThrowsInstanceOf(() => Int32x4.fromFloat64x2(g), RangeError);
-
-  // Testing high boundaries
-  // double(0, 1023 + 30, 0) < INT32_MAX < double(0, 1023 + 31, 0), so the
-  // lowest exactly representable quantity at this scale is 2**(-52 + 30) ==
-  // 2**-22.
-  assertEq(makeDouble(0, 1023 + 30, 0) + Math.pow(2, -22), makeDouble(0, 1023 + 30, 1));
-  assertEq(makeDouble(0, 1023 + 30, 0) + Math.pow(2, -23), makeDouble(0, 1023 + 30, 0));
-
-  var g = Float64x2(INT32_MAX, 0);
-  assertEqX4(Int32x4.fromFloat64x2(g), [INT32_MAX, 0, 0, 0]);
-
-  var g = Float64x2(INT32_MAX + Math.pow(2, -22), 0);
-  assertThrowsInstanceOf(() => Int32x4.fromFloat64x2(g), RangeError);
-
-  // Testing low boundaries
-  assertEq(makeDouble(1, 1023 + 31, 0), INT32_MIN);
-
-  var g = Float64x2(makeDouble(1, 1023 + 31, 0), 0);
-  assertEqX4(Int32x4.fromFloat64x2(g), [INT32_MIN, 0, 0, 0]);
-
-  var g = Float64x2(makeDouble(1, 1023 + 31, 1), 0);
-  assertThrowsInstanceOf(() => Int32x4.fromFloat64x2(g), RangeError);
-
-}
-
 function testInt32x4FromFloat64x2Bits() {
   var valsExp = [
     [[1.0, 2.0], [0x00000000, 0x3FF00000, 0x00000000, 0x40000000]],
     [[+Infinity, -Infinity], [0x00000000, 0x7ff00000, 0x00000000, -0x100000]],
     [[-0, NaN], [0x00000000, -0x80000000, 0x00000000, 0x7ff80000]],
     [[1.0000006400213732, 2.0000002532866263], [-0x543210ee, 0x3ff00000, 0x21fedcba, 0x40000000]]
   ];
 
@@ -557,43 +429,39 @@ function testInt16x8FromInt32x4Bits() {
     var i = Int32x4(...v);
     assertEqX8(Int16x8.fromInt32x4Bits(i), expected(i, ArrayBuffer));
     if (typeof SharedArrayBuffer != "undefined")
       assertEqX8(Int16x8.fromInt32x4Bits(i), expected(i, SharedArrayBuffer));
   }
 }
 
 function test() {
-  testFloat32x4FromFloat64x2();
   testFloat32x4FromFloat64x2Bits();
   testFloat32x4FromInt8x16Bits();
   testFloat32x4FromInt16x8Bits();
   testFloat32x4FromInt32x4();
   testFloat32x4FromInt32x4Bits();
 
-  testFloat64x2FromFloat32x4();
   testFloat64x2FromFloat32x4Bits();
   testFloat64x2FromInt8x16Bits();
   testFloat64x2FromInt16x8Bits();
-  testFloat64x2FromInt32x4();
   testFloat64x2FromInt32x4Bits();
 
   testInt8x16FromFloat32x4Bits();
   testInt8x16FromFloat64x2Bits();
   testInt8x16FromInt16x8Bits();
   testInt8x16FromInt32x4Bits();
 
   testInt16x8FromFloat32x4Bits();
   testInt16x8FromFloat64x2Bits();
   testInt16x8FromInt8x16Bits();
   testInt16x8FromInt32x4Bits();
 
   testInt32x4FromFloat32x4();
   testInt32x4FromFloat32x4Bits();
-  testInt32x4FromFloat64x2();
   testInt32x4FromFloat64x2Bits();
   testInt32x4FromInt8x16Bits();
   testInt32x4FromInt16x8Bits();
 
   if (typeof reportCompare === "function") {
     reportCompare(true, true);
   }
 }