expand fcvttg js tests to also test conversion to u32/i64/u64
authorJacob Lifshay <programmerjake@gmail.com>
Wed, 17 May 2023 02:11:24 +0000 (19:11 -0700)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 2 Jun 2023 18:51:18 +0000 (19:51 +0100)
src/openpower/test/fmv_fcvt/fmv_fcvt.py

index 3372deeb61eb086ac3b7ed05fda2cc536bf2e02e..961f08130fec2f68d30a2ae73528af86e22fce4a 100644 (file)
@@ -8,15 +8,36 @@ import struct
 import math
 
 
+def fp_bits_add(fp, amount):
+    """add `amount` to the IEEE 754 bits representing `fp`"""
+    bits = struct.unpack("<Q", struct.pack("<d", fp))[0]
+    bits += amount
+    return struct.unpack("<d", struct.pack("<Q", bits))[0]
+
+
 class FMvFCvtCases(TestAccumulatorBase):
-    def js_toint(self, inp, expected, test_title="", inp_bits=None):
+    def js_toint(
+        self, inp, expected=None, test_title="", inp_bits=None,
+        signed=True, _32bit=True,
+    ):
         inp = float(inp)
         if inp_bits is None:
             inp_bits = struct.unpack("<Q", struct.pack("<d", inp))[0]
+        if expected is None:
+            if math.isfinite(inp):
+                expected = math.trunc(inp)
+            else:
+                expected = 0
+            if _32bit:
+                expected %= 2 ** 32
+                if signed and expected >> 31:
+                    expected -= 2 ** 32
         expected %= 2 ** 64
+        IT = (not signed) + (not _32bit) * 2
         with self.subTest(inp=inp.hex(), inp_bits=hex(inp_bits),
-                          expected=hex(expected), test_title=test_title):
-            lst = list(SVP64Asm(["fcvttg 3,0,5,0"]))
+                          expected=hex(expected), test_title=test_title,
+                          signed=signed, _32bit=_32bit):
+            lst = list(SVP64Asm([f"fcvttg 3,0,5,{IT}"]))
             gprs = [0] * 32
             fprs = [0] * 32
             fprs[0] = inp_bits
@@ -26,9 +47,15 @@ class FMvFCvtCases(TestAccumulatorBase):
             if math.isnan(inp) and (inp_bits & 2 ** 51) == 0:  # SNaN
                 fpscr.VXSNAN = 1
                 fpscr.FX = 1
-
+            max_v = 2 ** 64 - 1
+            if _32bit:
+                max_v >>= 32
+            min_v = 0
+            if signed:
+                max_v >>= 1
+                min_v = ~max_v
             if not math.isfinite(inp) or not (
-                    -0x8000_0000 <= math.trunc(inp) <= 0x7fff_ffff):
+                    min_v <= math.trunc(inp) <= max_v):
                 fpscr.VXCVI = 1
                 fpscr.FX = 1
             elif math.trunc(inp) != inp:  # inexact
@@ -166,6 +193,171 @@ class FMvFCvtCases(TestAccumulatorBase):
         self.js_toint(max_fraction, 0)
         self.js_toint(-max_fraction, 0)
 
+    def case_js_touint32(self):
+        min_value = pow(2, -1074)
+        # test cases from:
+        # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/touint32.js
+        # with identical copyright notice as in case_js_toint32
+        self.js_toint(0, 0, "0", signed=False)
+        self.js_toint(-0, 0, "-0", signed=False)
+        self.js_toint(math.inf, 0, "Infinity", signed=False)
+        self.js_toint(-math.inf, 0, "-Infinity", signed=False)
+        self.js_toint(math.nan, 0, "NaN", signed=False)
+        self.js_toint(math.nan, 0, "SNaN", inp_bits=0x7ff0_0000_0000_0001,
+                      signed=False)
+        self.js_toint(min_value, 0, "MIN", signed=False)
+        self.js_toint(-min_value, 0, "-MIN", signed=False)
+        self.js_toint(0.1, 0, "0.1", signed=False)
+        self.js_toint(-0.1, 0, "-0.1", signed=False)
+        self.js_toint(1, 1, "1", signed=False)
+        self.js_toint(1.1, 1, "1.1", signed=False)
+        self.js_toint(-1, 4294967295, "-1", signed=False)
+        self.js_toint(-1.1, 4294967295, "-1.1", signed=False)
+        self.js_toint(2147483647, 2147483647, "2147483647", signed=False)
+        self.js_toint(2147483648, 2147483648, "2147483648", signed=False)
+        self.js_toint(2147483649, 2147483649, "2147483649", signed=False)
+        self.js_toint(4294967295, 4294967295, "4294967295", signed=False)
+        self.js_toint(4294967296, 0, "4294967296", signed=False)
+        self.js_toint(4294967297, 1, "4294967297", signed=False)
+        self.js_toint(-2147483647, 2147483649, "-2147483647", signed=False)
+        self.js_toint(-2147483648, 2147483648, "-2147483648", signed=False)
+        self.js_toint(-2147483649, 2147483647, "-2147483649", signed=False)
+        self.js_toint(-4294967295, 1, "-4294967295", signed=False)
+        self.js_toint(-4294967296, 0, "-4294967296", signed=False)
+        self.js_toint(-4294967297, 4294967295, "-4294967297", signed=False)
+
+    def case_js_toint64(self):
+        # 64-bit equivalent of javascript's toint32
+        min_value = pow(2, -1074)
+        # test cases derived from:
+        # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/toint32.js
+        # with identical copyright notice as in case_js_toint32
+
+        self.js_toint(math.inf, 0, "Inf", _32bit=False)
+        self.js_toint(-math.inf, 0, "-Inf", _32bit=False)
+        self.js_toint(math.nan, 0, "NaN", _32bit=False)
+        self.js_toint(math.nan, 0, "SNaN",
+                      inp_bits=0x7ff0_0000_0000_0001, _32bit=False)
+        self.js_toint(0.0, 0, "zero", _32bit=False)
+        self.js_toint(-0.0, 0, "-zero", _32bit=False)
+        self.js_toint(min_value, 0, _32bit=False)
+        self.js_toint(-min_value, 0, _32bit=False)
+        self.js_toint(0.1, 0, _32bit=False)
+        self.js_toint(-0.1, 0, _32bit=False)
+        self.js_toint(1, 1, "one", _32bit=False)
+        self.js_toint(1.1, 1, "onepointone", _32bit=False)
+        self.js_toint(-1, -1, "-one", _32bit=False)
+        self.js_toint(0.6, 0, "truncate positive (0.6)", _32bit=False)
+        self.js_toint(1.6, 1, "truncate positive (1.6)", _32bit=False)
+        self.js_toint(-0.6, 0, "truncate negative (-0.6)", _32bit=False)
+        self.js_toint(-1.6, -1, "truncate negative (-1.6)", _32bit=False)
+        self.js_toint(fp_bits_add(2**63, -1), _32bit=False)
+        self.js_toint(2**63, _32bit=False)
+        self.js_toint(fp_bits_add(2**63, 1), _32bit=False)
+        self.js_toint(fp_bits_add(2**64, -1), _32bit=False)
+        self.js_toint(2**64, 0, _32bit=False)
+        self.js_toint(fp_bits_add(2**64, 1), _32bit=False)
+        self.js_toint(-fp_bits_add(2**63, -1), _32bit=False)
+        self.js_toint(-(2**63), _32bit=False)
+        self.js_toint(-fp_bits_add(2**63, 1), _32bit=False)
+        self.js_toint(-fp_bits_add(2**64, -1), _32bit=False)
+        self.js_toint(-(2**64), 0, _32bit=False)
+        self.js_toint(-fp_bits_add(2**64, 1), _32bit=False)
+        self.js_toint(2147483648.25, _32bit=False)
+        self.js_toint(2147483648.5, _32bit=False)
+        self.js_toint(2147483648.75, _32bit=False)
+        self.js_toint(4294967295.25, _32bit=False)
+        self.js_toint(4294967295.5, _32bit=False)
+        self.js_toint(4294967295.75, _32bit=False)
+        self.js_toint(3000000000.25, _32bit=False)
+        self.js_toint(3000000000.5, _32bit=False)
+        self.js_toint(3000000000.75, _32bit=False)
+        self.js_toint(-2147483648.25, _32bit=False)
+        self.js_toint(-2147483648.5, _32bit=False)
+        self.js_toint(-2147483648.75, _32bit=False)
+        self.js_toint(-4294967295.25, _32bit=False)
+        self.js_toint(-4294967295.5, _32bit=False)
+        self.js_toint(-4294967295.75, _32bit=False)
+        self.js_toint(-3000000000.25, _32bit=False)
+        self.js_toint(-3000000000.5, _32bit=False)
+        self.js_toint(-3000000000.75, _32bit=False)
+        base = pow(2, 64)
+        self.js_toint(base + 0, _32bit=False)
+        self.js_toint(base + 1117, _32bit=False)
+        self.js_toint(base + 2234, _32bit=False)
+        self.js_toint(base + 3351, _32bit=False)
+        self.js_toint(base + 4468, _32bit=False)
+        self.js_toint(base + 5585, _32bit=False)
+        self.js_toint(base + 6702, _32bit=False)
+        self.js_toint(base + 7819, _32bit=False)
+        self.js_toint(base + 8936, _32bit=False)
+        self.js_toint(base + 10053, _32bit=False)
+        self.js_toint(base + 11170, _32bit=False)
+        self.js_toint(base + 12287, _32bit=False)
+        self.js_toint(base + 13404, _32bit=False)
+        self.js_toint(base + 14521, _32bit=False)
+        self.js_toint(base + 15638, _32bit=False)
+        self.js_toint(base + 16755, _32bit=False)
+        self.js_toint(base + 17872, _32bit=False)
+        self.js_toint(base + 18989, _32bit=False)
+        self.js_toint(base + 20106, _32bit=False)
+        self.js_toint(base + 21223, _32bit=False)
+        self.js_toint(base + 22340, _32bit=False)
+        self.js_toint(base + 23457, _32bit=False)
+        self.js_toint(base + 24574, _32bit=False)
+        self.js_toint(base + 25691, _32bit=False)
+        self.js_toint(base + 26808, _32bit=False)
+        self.js_toint(base + 27925, _32bit=False)
+        self.js_toint(base + 29042, _32bit=False)
+        self.js_toint(base + 30159, _32bit=False)
+        self.js_toint(base + 31276, _32bit=False)
+        # bignum is (2 ^ 53 - 1) * 2 ^ 31 - highest number with bit 31 set.
+        bignum = pow(2, 84) - pow(2, 31)
+        self.js_toint(bignum, _32bit=False)
+        self.js_toint(-bignum, _32bit=False)
+        self.js_toint(2 * bignum, _32bit=False)
+        self.js_toint(-(2 * bignum), _32bit=False)
+        self.js_toint(bignum - pow(2, 31), _32bit=False)
+        self.js_toint(-(bignum - pow(2, 31)), _32bit=False)
+        # max_fraction is largest number below 1.
+        max_fraction = (1 - pow(2, -53))
+        self.js_toint(max_fraction, 0, _32bit=False)
+        self.js_toint(-max_fraction, 0, _32bit=False)
+
+    def case_js_touint64(self):
+        # 64-bit equivalent of javascript's touint32
+        min_value = pow(2, -1074)
+        # test cases derived from:
+        # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/touint32.js
+        # with identical copyright notice as in case_js_toint32
+        self.js_toint(0, 0, "0", signed=False, _32bit=False)
+        self.js_toint(-0, 0, "-0", signed=False, _32bit=False)
+        self.js_toint(math.inf, 0, "Infinity", signed=False, _32bit=False)
+        self.js_toint(-math.inf, 0, "-Infinity", signed=False, _32bit=False)
+        self.js_toint(math.nan, 0, "NaN", signed=False, _32bit=False)
+        self.js_toint(math.nan, 0, "SNaN", inp_bits=0x7ff0_0000_0000_0001,
+                      signed=False, _32bit=False)
+        self.js_toint(min_value, 0, "MIN", signed=False, _32bit=False)
+        self.js_toint(-min_value, 0, "-MIN", signed=False, _32bit=False)
+        self.js_toint(0.1, 0, "0.1", signed=False, _32bit=False)
+        self.js_toint(-0.1, 0, "-0.1", signed=False, _32bit=False)
+        self.js_toint(1, 1, "1", signed=False, _32bit=False)
+        self.js_toint(1.1, 1, "1.1", signed=False, _32bit=False)
+        self.js_toint(-1, 2**64 - 1, "-1", signed=False, _32bit=False)
+        self.js_toint(-1.1, 2**64 - 1, "-1.1", signed=False, _32bit=False)
+        self.js_toint(fp_bits_add(2**63, -1), signed=False, _32bit=False)
+        self.js_toint(2**63, signed=False, _32bit=False)
+        self.js_toint(fp_bits_add(2**63, 1), signed=False, _32bit=False)
+        self.js_toint(fp_bits_add(2**64, -1), signed=False, _32bit=False)
+        self.js_toint(2**64, 0, signed=False, _32bit=False)
+        self.js_toint(fp_bits_add(2**64, 1), signed=False, _32bit=False)
+        self.js_toint(-fp_bits_add(2**63, -1), signed=False, _32bit=False)
+        self.js_toint(-(2**63), signed=False, _32bit=False)
+        self.js_toint(-fp_bits_add(2**63, 1), signed=False, _32bit=False)
+        self.js_toint(-fp_bits_add(2**64, -1), signed=False, _32bit=False)
+        self.js_toint(-(2**64), 0, signed=False, _32bit=False)
+        self.js_toint(-fp_bits_add(2**64, 1), signed=False, _32bit=False)
+
 
 class SVP64FMvFCvtCases(TestAccumulatorBase):
     @skip_case("FIXME: rewrite to fmv/fcvt tests")