Add sfclass/dfclass FP classification tests, unsigned-to-double
conversions, and dfmpyfix denormal fixup tests.

Signed-off-by: Brian Cain <[email protected]>
---
 tests/tcg/hexagon/fpstuff.c | 175 ++++++++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)

diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c
index 6aadaccabdf..7561f31cdc3 100644
--- a/tests/tcg/hexagon/fpstuff.c
+++ b/tests/tcg/hexagon/fpstuff.c
@@ -711,6 +711,176 @@ static void check_dfmpyxx(void)
     check64(res64, 0x7fefffffffffffffULL);
 }
 
+/*
+ * sfclass mask bits:
+ *   bit 0: positive/negative zero
+ *   bit 1: positive/negative normal
+ *   bit 2: positive/negative denormal
+ *   bit 3: positive/negative infinity
+ *   bit 4: positive/negative NaN
+ */
+#define TEST_SFCLASS(VAL, MASK, EXPECT) \
+    do { \
+        uint32_t res; \
+        asm("%[res] = #0\n\t" \
+            "p0 = sfclass(%[val], #" #MASK ")\n\t" \
+            "if (p0) %[res] = #1\n\t" \
+            : [res] "=&r"(res) \
+            : [val] "r"(VAL) \
+            : "p0"); \
+        check32(res, EXPECT); \
+    } while (0)
+
+static void check_sfclass(void)
+{
+    /* Zero: mask bit 0 */
+    TEST_SFCLASS(SF_zero, 0x01, 1);
+    TEST_SFCLASS(SF_zero_neg, 0x01, 1);
+    TEST_SFCLASS(SF_zero, 0x02, 0);
+
+    /* Normal: mask bit 1 */
+    TEST_SFCLASS(SF_one, 0x02, 1);
+    TEST_SFCLASS(SF_one, 0x01, 0);
+
+    /* Denormal: mask bit 2 */
+    TEST_SFCLASS(SF_denorm, 0x04, 1);
+    TEST_SFCLASS(SF_denorm, 0x01, 0);
+
+    /* Infinity: mask bit 3 */
+    TEST_SFCLASS(SF_INF, 0x08, 1);
+    TEST_SFCLASS(SF_INF, 0x01, 0);
+
+    /* NaN: mask bit 4 */
+    TEST_SFCLASS(SF_QNaN, 0x10, 1);
+    TEST_SFCLASS(SF_SNaN, 0x10, 1);
+    TEST_SFCLASS(SF_QNaN, 0x01, 0);
+
+    /* Combined: any class (all bits set) */
+    TEST_SFCLASS(SF_one, 0x1f, 1);
+}
+
+/*
+ * dfclass mask bits are the same as sfclass.
+ */
+static const uint64_t DF_INF = 0x7ff0000000000000ULL;
+static const uint64_t DF_denorm = 0x0000000000000001ULL;
+static const uint64_t DF_neg_one = 0xbff0000000000000ULL;
+
+#define TEST_DFCLASS(VAL, MASK, EXPECT) \
+    do { \
+        uint32_t res; \
+        asm("%[res] = #0\n\t" \
+            "p0 = dfclass(%[val], #" #MASK ")\n\t" \
+            "if (p0) %[res] = #1\n\t" \
+            : [res] "=&r"(res) \
+            : [val] "r"(VAL) \
+            : "p0"); \
+        check32(res, EXPECT); \
+    } while (0)
+
+static void check_dfclass(void)
+{
+    /* Zero: mask bit 0 */
+    TEST_DFCLASS(DF_zero, 0x01, 1);
+    TEST_DFCLASS(DF_zero_neg, 0x01, 1);
+    TEST_DFCLASS(DF_zero, 0x02, 0);
+
+    /* Normal: mask bit 1 */
+    TEST_DFCLASS(DF_one, 0x02, 1);
+    TEST_DFCLASS(DF_neg_one, 0x02, 1);
+    TEST_DFCLASS(DF_one, 0x01, 0);
+
+    /* Denormal: mask bit 2 */
+    TEST_DFCLASS(DF_denorm, 0x04, 1);
+    TEST_DFCLASS(DF_denorm, 0x01, 0);
+
+    /* Infinity: mask bit 3 */
+    TEST_DFCLASS(DF_INF, 0x08, 1);
+    TEST_DFCLASS(DF_INF, 0x01, 0);
+
+    /* NaN: mask bit 4 */
+    TEST_DFCLASS(DF_QNaN, 0x10, 1);
+    TEST_DFCLASS(DF_SNaN, 0x10, 1);
+    TEST_DFCLASS(DF_QNaN, 0x01, 0);
+}
+
+/* Rdd = convert_uw2df(Rs) */
+static uint64_t conv_uw2df(uint32_t val)
+{
+    uint64_t result;
+
+    asm("%[res] = convert_uw2df(%[val])\n\t"
+        : [res] "=r"(result)
+        : [val] "r"(val));
+    return result;
+}
+
+static void check_conv_uw2df(void)
+{
+    check64(conv_uw2df(0), DF_zero);
+    check64(conv_uw2df(1), DF_one);
+    /* 100 -> 0x4059000000000000 */
+    check64(conv_uw2df(100), 0x4059000000000000ULL);
+    /* 0xFFFFFFFF -> 4294967295.0 = 0x41EFFFFFFFE00000 */
+    check64(conv_uw2df(0xFFFFFFFF), 0x41EFFFFFFFE00000ULL);
+}
+
+/* Rdd = convert_ud2df(Rss) */
+static uint64_t conv_ud2df(uint64_t val)
+{
+    uint64_t result;
+
+    asm("%[res] = convert_ud2df(%[val])\n\t"
+        : [res] "=r"(result)
+        : [val] "r"(val));
+    return result;
+}
+
+static void check_conv_ud2df(void)
+{
+    check64(conv_ud2df(0ULL), DF_zero);
+    check64(conv_ud2df(1ULL), DF_one);
+    /* 1000000 -> 0x412E848000000000 */
+    check64(conv_ud2df(1000000ULL), 0x412E848000000000ULL);
+}
+
+/* Rdd = dfmpyfix(Rss,Rtt) -- DF multiply denormal fixup */
+static uint64_t do_dfmpyfix(uint64_t a, uint64_t b)
+{
+    uint64_t result;
+
+    asm("%[res] = dfmpyfix(%[a], %[b])\n\t"
+        : [res] "=r"(result)
+        : [a] "r"(a), [b] "r"(b));
+    return result;
+}
+
+static void check_dfmpyfix(void)
+{
+    /*
+     * With two normal values (neither denormal, exps < 512),
+     * the result should be the first operand unchanged.
+     */
+    check64(do_dfmpyfix(DF_one, DF_one), DF_one);
+
+    /*
+     * Case: b is denormal AND a is normal with exp >= 512.
+     * a gets multiplied by 2^-52 (0x3cb0000000000000).
+     * a = 1.0, result = 1.0 * 2^-52 = 0x3cb0000000000000
+     */
+    check64(do_dfmpyfix(DF_one, DF_denorm), 0x3CB0000000000000ULL);
+
+    /*
+     * Case: a is denormal AND b is normal with exp >= 512.
+     * a gets multiplied by 2^52 (0x4330000000000000).
+     * a = smallest denorm = 2^-1074, b = 2^512 (biased exp 0x5ff).
+     * Result = 2^-1074 * 2^52 = 2^-1022 = smallest normal
+     *        = 0x0010000000000000
+     */
+    check64(do_dfmpyfix(DF_denorm, 0x5FF0000000000000ULL),
+            0x0010000000000000ULL);
+}
+
 int main()
 {
     check_compare_exception();
@@ -725,6 +895,11 @@ int main()
     check_float2int_convs();
     check_float_consts();
     check_dfmpyxx();
+    check_sfclass();
+    check_dfclass();
+    check_conv_uw2df();
+    check_conv_ud2df();
+    check_dfmpyfix();
 
     puts(err ? "FAIL" : "PASS");
     return err ? 1 : 0;
-- 
2.34.1

Reply via email to