]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-133304: workaround for RISC-V in PyFloat_Pack4/Unpack4() (#133328)
authorSergey B Kirpichev <skirpichev@gmail.com>
Sat, 3 May 2025 15:07:52 +0000 (18:07 +0300)
committerGitHub <noreply@github.com>
Sat, 3 May 2025 15:07:52 +0000 (17:07 +0200)
Lib/test/test_capi/test_float.py
Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-07-41-21.gh-issue-133304.YMuSne.rst [new file with mode: 0644]
Objects/floatobject.c

index c832207fef0c1aa6bfd75514a74c562c82b95e3c..f7efe0d02549a3b8a249fc71cc3002de47fad2f9 100644 (file)
@@ -199,13 +199,13 @@ class CAPIFloatTest(unittest.TestCase):
                     signaling = 0
                 quiet = int(not signaling)
                 if size == 8:
-                    payload = random.randint(signaling, 1 << 50)
+                    payload = random.randint(signaling, 0x7ffffffffffff)
                     i = (sign << 63) + (0x7ff << 52) + (quiet << 51) + payload
                 elif size == 4:
-                    payload = random.randint(signaling, 1 << 21)
+                    payload = random.randint(signaling, 0x3fffff)
                     i = (sign << 31) + (0xff << 23) + (quiet << 22) + payload
                 elif size == 2:
-                    payload = random.randint(signaling, 1 << 8)
+                    payload = random.randint(signaling, 0x1ff)
                     i = (sign << 15) + (0x1f << 10) + (quiet << 9) + payload
                 data = bytes.fromhex(f'{i:x}')
                 for endian in (BIG_ENDIAN, LITTLE_ENDIAN):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-07-41-21.gh-issue-133304.YMuSne.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-07-41-21.gh-issue-133304.YMuSne.rst
new file mode 100644 (file)
index 0000000..64ae40a
--- /dev/null
@@ -0,0 +1,2 @@
+Workaround NaN's "canonicalization" in :c:func:`PyFloat_Pack4`
+and :c:func:`PyFloat_Unpack4` on RISC-V.
index 692b6aa2cabd5ee48297d692ac26c454b0592027..93e1973d6b32fc707b9e7631dcd0f18043ac2ece 100644 (file)
@@ -2196,12 +2196,33 @@ PyFloat_Pack4(double x, char *data, int le)
             uint64_t v;
 
             memcpy(&v, &x, 8);
+#ifndef __riscv
             if ((v & (1ULL << 51)) == 0) {
                 uint32_t u32;
                 memcpy(&u32, &y, 4);
                 u32 &= ~(1 << 22); /* make sNaN */
                 memcpy(&y, &u32, 4);
             }
+#else
+            uint32_t u32;
+
+            memcpy(&u32, &y, 4);
+            if ((v & (1ULL << 51)) == 0) {
+                u32 &= ~(1 << 22);
+            }
+            /* Workaround RISC-V: "If a NaN value is converted to a
+             * different floating-point type, the result is the
+             * canonical NaN of the new type".  The canonical NaN here
+             * is a positive qNaN with zero payload. */
+            if (v & (1ULL << 63)) {
+                u32 |= (1 << 31); /* set sign */
+            }
+            /* add payload */
+            u32 -= (u32 & 0x3fffff);
+            u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
+
+            memcpy(&y, &u32, 4);
+#endif
         }
 
         unsigned char s[sizeof(float)];
@@ -2493,6 +2514,7 @@ PyFloat_Unpack4(const char *data, int le)
             uint32_t v;
             memcpy(&v, &x, 4);
 
+#ifndef __riscv
             if ((v & (1 << 22)) == 0) {
                 double y = x; /* will make qNaN double */
                 uint64_t u64;
@@ -2501,6 +2523,25 @@ PyFloat_Unpack4(const char *data, int le)
                 memcpy(&y, &u64, 8);
                 return y;
             }
+#else
+            double y = x;
+            uint64_t u64;
+
+            memcpy(&u64, &y, 8);
+            if ((v & (1 << 22)) == 0) {
+                u64 &= ~(1ULL << 51);
+            }
+            /* Workaround RISC-V, see PyFloat_Pack4() */
+            if (v & (1 << 31)) {
+                u64 |= (1ULL << 63); /* set sign */
+            }
+            /* add payload */
+            u64 -= (u64 & 0x7ffffffffffffULL);
+            u64 += ((v & 0x3fffffULL) << 29);
+
+            memcpy(&y, &u64, 8);
+            return y;
+#endif
         }
 
         return x;