Bug 1233111 - Add ecma_7 shift tests. r?bbouvier draft
authorJakob Stoklund Olesen <jolesen@mozilla.com>
Wed, 23 Dec 2015 09:52:39 -0800
changeset 317286 864faba2c96ef805a67ad72222c5773d818add9b
parent 317285 a32fa1ddce3805d4e4c5717c538ed349d8c4463c
child 317287 3dfaaa091673a5cf7a03bcda7a1e2a1c6326cdc8
push id8682
push userjolesen@mozilla.com
push dateWed, 23 Dec 2015 17:52:08 +0000
reviewersbbouvier
bugs1233111
milestone46.0a1
Bug 1233111 - Add ecma_7 shift tests. r?bbouvier Fix a bug in ShiftRightArithmetic when the underlying Elem type is unsigned. Need to cast to a signed type to so it sign-extends to int when shifting. Implement both logical and arithmetic right shift implementations for both signed and unsigned integers. This is needed to test our current implementation where both signed and unsigned SIMD types have the two shiftRightArithmeticByScalar() and shiftRightLogicalByScalar() functions. Soon, shiftRightArithmeticByScalar() and shiftRightLogicalByScalar() will be replaced by a single shiftRightByScalar() function whose behavior is dependent on the signedness of the underlying type.
js/src/builtin/SIMD.cpp
js/src/tests/ecma_7/SIMD/shifts.js
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -682,18 +682,19 @@ template<typename T>
 struct ShiftLeft {
     static T apply(T v, int32_t bits) {
         return uint32_t(bits) >= sizeof(T) * 8 ? 0 : v << bits;
     }
 };
 template<typename T>
 struct ShiftRightArithmetic {
     static T apply(T v, int32_t bits) {
+        typedef typename mozilla::MakeSigned<T>::Type SignedT;
         uint32_t maxBits = sizeof(T) * 8;
-        return v >> (uint32_t(bits) >= maxBits ? maxBits - 1 : bits);
+        return SignedT(v) >> (uint32_t(bits) >= maxBits ? maxBits - 1 : bits);
     }
 };
 template<typename T>
 struct ShiftRightLogical {
     static T apply(T v, int32_t bits) {
         return uint32_t(bits) >= sizeof(T) * 8 ? 0 : uint32_t(v) >> bits;
     }
 };
--- a/js/src/tests/ecma_7/SIMD/shifts.js
+++ b/js/src/tests/ecma_7/SIMD/shifts.js
@@ -3,111 +3,212 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * https://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var Int8x16 = SIMD.Int8x16;
 var Int16x8 = SIMD.Int16x8;
 var Int32x4 = SIMD.Int32x4;
+var Uint8x16 = SIMD.Uint8x16;
+var Uint16x8 = SIMD.Uint16x8;
+var Uint32x4 = SIMD.Uint32x4;
 
+// Int8 shifts.
 function lsh8(a, b) {
     return (b >>> 0) >= 8 ? 0 : (a << b) << 24 >> 24;
 }
-function rsh8(a, b) {
+function rsha8(a, b) {
     return (a >> Math.min(b >>> 0, 7)) << 24 >> 24;
 }
-function ursh8(a, b) {
+function rshl8(a, b) {
     return (b >>> 0) >= 8 ? 0 : (a >>> b) << 24 >> 24;
 }
 
+// Int16 shifts.
 function lsh16(a, b) {
     return (b >>> 0) >= 16 ? 0 : (a << b) << 16 >> 16;
 }
-function rsh16(a, b) {
+function rsha16(a, b) {
     return (a >> Math.min(b >>> 0, 15)) << 16 >> 16;
 }
-function ursh16(a, b) {
+function rshl16(a, b) {
     return (b >>> 0) >= 16 ? 0 : (a >>> b) << 16 >> 16;
 }
 
+// Int32 shifts.
 function lsh32(a, b) {
     return (b >>> 0) >= 32 ? 0 : (a << b) | 0;
 }
-function rsh32(a, b) {
+function rsha32(a, b) {
     return (a >> Math.min(b >>> 0, 31)) | 0;
 }
-function ursh32(a, b) {
+function rshl32(a, b) {
     return (b >>> 0) >= 32 ? 0 : (a >>> b) | 0;
 }
 
+// Uint8 shifts.
+function ulsh8(a, b) {
+    return (b >>> 0) >= 8 ? 0 : (a << b) << 24 >>> 24;
+}
+function ursha8(a, b) {
+    return ((a << 24 >> 24) >> Math.min(b >>> 0, 7)) << 24 >>> 24;
+}
+function urshl8(a, b) {
+    return (b >>> 0) >= 8 ? 0 : (a >>> b) << 24 >>> 24;
+}
+
+// Uint16 shifts.
+function ulsh16(a, b) {
+    return (b >>> 0) >= 16 ? 0 : (a << b) << 16 >>> 16;
+}
+function ursha16(a, b) {
+    return ((a << 16 >> 16) >> Math.min(b >>> 0, 15)) << 16 >>> 16;
+}
+function urshl16(a, b) {
+    return (b >>> 0) >= 16 ? 0 : (a >>> b) << 16 >>> 16;
+}
+
+// Uint32 shifts.
+function ulsh32(a, b) {
+    return (b >>> 0) >= 32 ? 0 : (a << b) >>> 0;
+}
+function ursha32(a, b) {
+    return ((a | 0) >> Math.min(b >>> 0, 31)) >>> 0;
+}
+function urshl32(a, b) {
+    return (b >>> 0) >= 32 ? 0 : (a >>> b) >>> 0;
+}
+
 function test() {
   function TestError() {};
 
   var good = {valueOf: () => 21};
   var bad = {valueOf: () => {throw new TestError(); }};
 
   for (var v of [
             Int8x16(-1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15, 16),
             Int8x16(INT8_MAX, INT8_MIN, INT8_MAX - 1, INT8_MIN + 1)
        ])
   {
       for (var bits = -2; bits < 12; bits++) {
           testBinaryScalarFunc(v, bits, Int8x16.shiftLeftByScalar, lsh8);
-          testBinaryScalarFunc(v, bits, Int8x16.shiftRightArithmeticByScalar, rsh8);
-          testBinaryScalarFunc(v, bits, Int8x16.shiftRightLogicalByScalar, ursh8);
+          testBinaryScalarFunc(v, bits, Int8x16.shiftRightArithmeticByScalar, rsha8);
+          testBinaryScalarFunc(v, bits, Int8x16.shiftRightLogicalByScalar, rshl8);
       }
       // Test that the shift count is coerced to an int32.
       testBinaryScalarFunc(v, undefined, Int8x16.shiftLeftByScalar, lsh8);
       testBinaryScalarFunc(v, 3.5, Int8x16.shiftLeftByScalar, lsh8);
       testBinaryScalarFunc(v, good, Int8x16.shiftLeftByScalar, lsh8);
   }
   for (var v of [
             Int16x8(-1, 2, -3, 4, -5, 6, -7, 8),
             Int16x8(INT16_MAX, INT16_MIN, INT16_MAX - 1, INT16_MIN + 1)
        ])
   {
       for (var bits = -2; bits < 20; bits++) {
           testBinaryScalarFunc(v, bits, Int16x8.shiftLeftByScalar, lsh16);
-          testBinaryScalarFunc(v, bits, Int16x8.shiftRightArithmeticByScalar, rsh16);
-          testBinaryScalarFunc(v, bits, Int16x8.shiftRightLogicalByScalar, ursh16);
+          testBinaryScalarFunc(v, bits, Int16x8.shiftRightArithmeticByScalar, rsha16);
+          testBinaryScalarFunc(v, bits, Int16x8.shiftRightLogicalByScalar, rshl16);
       }
       // Test that the shift count is coerced to an int32.
       testBinaryScalarFunc(v, undefined, Int16x8.shiftLeftByScalar, lsh16);
       testBinaryScalarFunc(v, 3.5, Int16x8.shiftLeftByScalar, lsh16);
       testBinaryScalarFunc(v, good, Int16x8.shiftLeftByScalar, lsh16);
   }
   for (var v of [
             Int32x4(-1, 2, -3, 4),
             Int32x4(INT32_MAX, INT32_MIN, INT32_MAX - 1, INT32_MIN + 1)
        ])
   {
       for (var bits = -2; bits < 36; bits++) {
           testBinaryScalarFunc(v, bits, Int32x4.shiftLeftByScalar, lsh32);
-          testBinaryScalarFunc(v, bits, Int32x4.shiftRightArithmeticByScalar, rsh32);
-          testBinaryScalarFunc(v, bits, Int32x4.shiftRightLogicalByScalar, ursh32);
+          testBinaryScalarFunc(v, bits, Int32x4.shiftRightArithmeticByScalar, rsha32);
+          testBinaryScalarFunc(v, bits, Int32x4.shiftRightLogicalByScalar, rshl32);
       }
       // Test that the shift count is coerced to an int32.
       testBinaryScalarFunc(v, undefined, Int32x4.shiftLeftByScalar, lsh32);
       testBinaryScalarFunc(v, 3.5, Int32x4.shiftLeftByScalar, lsh32);
       testBinaryScalarFunc(v, good, Int32x4.shiftLeftByScalar, lsh32);
   }
 
+  for (var v of [
+            Uint8x16(-1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15, 16),
+            Uint8x16(INT8_MAX, INT8_MIN, INT8_MAX - 1, INT8_MIN + 1, UINT8_MAX, UINT8_MAX - 1)
+       ])
+  {
+      for (var bits = -2; bits < 12; bits++) {
+          testBinaryScalarFunc(v, bits, Uint8x16.shiftLeftByScalar, ulsh8);
+          testBinaryScalarFunc(v, bits, Uint8x16.shiftRightArithmeticByScalar, ursha8);
+          testBinaryScalarFunc(v, bits, Uint8x16.shiftRightLogicalByScalar, urshl8);
+      }
+      // Test that the shift count is coerced to an int32.
+      testBinaryScalarFunc(v, undefined, Uint8x16.shiftLeftByScalar, ulsh8);
+      testBinaryScalarFunc(v, 3.5, Uint8x16.shiftLeftByScalar, ulsh8);
+      testBinaryScalarFunc(v, good, Uint8x16.shiftLeftByScalar, ulsh8);
+  }
+  for (var v of [
+            Uint16x8(-1, 2, -3, 4, -5, 6, -7, 8),
+            Uint16x8(INT16_MAX, INT16_MIN, INT16_MAX - 1, INT16_MIN + 1, UINT16_MAX, UINT16_MAX - 1)
+       ])
+  {
+      for (var bits = -2; bits < 20; bits++) {
+          testBinaryScalarFunc(v, bits, Uint16x8.shiftLeftByScalar, ulsh16);
+          testBinaryScalarFunc(v, bits, Uint16x8.shiftRightArithmeticByScalar, ursha16);
+          testBinaryScalarFunc(v, bits, Uint16x8.shiftRightLogicalByScalar, urshl16);
+      }
+      // Test that the shift count is coerced to an int32.
+      testBinaryScalarFunc(v, undefined, Uint16x8.shiftLeftByScalar, ulsh16);
+      testBinaryScalarFunc(v, 3.5, Uint16x8.shiftLeftByScalar, ulsh16);
+      testBinaryScalarFunc(v, good, Uint16x8.shiftLeftByScalar, ulsh16);
+  }
+  for (var v of [
+            Uint32x4(-1, 2, -3, 4),
+            Uint32x4(UINT32_MAX, UINT32_MAX - 1, 0, 1),
+            Uint32x4(INT32_MAX, INT32_MIN, INT32_MAX - 1, INT32_MIN + 1)
+       ])
+  {
+      for (var bits = -2; bits < 36; bits++) {
+          testBinaryScalarFunc(v, bits, Uint32x4.shiftLeftByScalar, ulsh32);
+          testBinaryScalarFunc(v, bits, Uint32x4.shiftRightArithmeticByScalar, ursha32);
+          testBinaryScalarFunc(v, bits, Uint32x4.shiftRightLogicalByScalar, urshl32);
+      }
+      // Test that the shift count is coerced to an int32.
+      testBinaryScalarFunc(v, undefined, Uint32x4.shiftLeftByScalar, ulsh32);
+      testBinaryScalarFunc(v, 3.5, Uint32x4.shiftLeftByScalar, ulsh32);
+      testBinaryScalarFunc(v, good, Uint32x4.shiftLeftByScalar, ulsh32);
+  }
+
   var v = SIMD.Int8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
   assertThrowsInstanceOf(() => SIMD.Int8x16.shiftLeftByScalar(v, bad), TestError);
   assertThrowsInstanceOf(() => SIMD.Int8x16.shiftRightArithmeticByScalar(v, bad), TestError);
   assertThrowsInstanceOf(() => SIMD.Int8x16.shiftRightLogicalByScalar(v, bad), TestError);
 
   var v = SIMD.Int16x8(1,2,3,4,5,6,7,8);
   assertThrowsInstanceOf(() => SIMD.Int16x8.shiftLeftByScalar(v, bad), TestError);
   assertThrowsInstanceOf(() => SIMD.Int16x8.shiftRightArithmeticByScalar(v, bad), TestError);
   assertThrowsInstanceOf(() => SIMD.Int16x8.shiftRightLogicalByScalar(v, bad), TestError);
 
   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);
 
+  var v = SIMD.Uint8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+  assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftLeftByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftRightArithmeticByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftRightLogicalByScalar(v, bad), TestError);
+
+  var v = SIMD.Uint16x8(1,2,3,4,5,6,7,8);
+  assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftLeftByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftRightArithmeticByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftRightLogicalByScalar(v, bad), TestError);
+
+  var v = SIMD.Uint32x4(1,2,3,4);
+  assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftLeftByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftRightArithmeticByScalar(v, bad), TestError);
+  assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftRightLogicalByScalar(v, bad), TestError);
+
   if (typeof reportCompare === "function")
     reportCompare(true, true);
 }
 
 test();