https://github.com/python/cpython/commit/f16f06f336ed9e0a2f12a12b26f176cbe831d2b1
commit: f16f06f336ed9e0a2f12a12b26f176cbe831d2b1
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: vstinner <[email protected]>
date: 2025-05-03T17:07:52+02:00
summary:
gh-133304: workaround for RISC-V in PyFloat_Pack4/Unpack4() (#133328)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-07-41-21.gh-issue-133304.YMuSne.rst
M Lib/test/test_capi/test_float.py
M Objects/floatobject.c
diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py
index c832207fef0c1a..f7efe0d02549a3 100644
--- a/Lib/test/test_capi/test_float.py
+++ b/Lib/test/test_capi/test_float.py
@@ -199,13 +199,13 @@ def test_pack_unpack_roundtrip_for_nans(self):
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
index 00000000000000..64ae40a79a4d9c
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-07-41-21.gh-issue-133304.YMuSne.rst
@@ -0,0 +1,2 @@
+Workaround NaN's "canonicalization" in :c:func:`PyFloat_Pack4`
+and :c:func:`PyFloat_Unpack4` on RISC-V.
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 692b6aa2cabd5e..93e1973d6b32fc 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -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;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]