Skip to content

Commit a568c94

Browse files
committed
gh-133304: workaround for RISC-V in PyFloat_Pack4()
1 parent 345fdce commit a568c94

File tree

3 files changed

+20
-6
lines changed

3 files changed

+20
-6
lines changed

Lib/test/test_capi/test_float.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,13 @@ def test_pack_unpack_roundtrip_for_nans(self):
199199
signaling = 0
200200
quiet = int(not signaling)
201201
if size == 8:
202-
payload = random.randint(signaling, 1 << 50)
202+
payload = random.randint(signaling, 0x7ffffffffffff)
203203
i = (sign << 63) + (0x7ff << 52) + (quiet << 51) + payload
204204
elif size == 4:
205-
payload = random.randint(signaling, 1 << 21)
205+
payload = random.randint(signaling, 0x3fffff)
206206
i = (sign << 31) + (0xff << 23) + (quiet << 22) + payload
207207
elif size == 2:
208-
payload = random.randint(signaling, 1 << 8)
208+
payload = random.randint(signaling, 0x1ff)
209209
i = (sign << 15) + (0x1f << 10) + (quiet << 9) + payload
210210
data = bytes.fromhex(f'{i:x}')
211211
for endian in (BIG_ENDIAN, LITTLE_ENDIAN):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Workaround NaN's "canonicalization" in :c:func:`PyFloat_Pack4` on RISC-V.

Objects/floatobject.c

+16-3
Original file line numberDiff line numberDiff line change
@@ -2194,14 +2194,27 @@ PyFloat_Pack4(double x, char *data, int le)
21942194
/* correct y if x was a sNaN, transformed to qNaN by conversion */
21952195
if (isnan(x)) {
21962196
uint64_t v;
2197+
uint32_t u32;
21972198

21982199
memcpy(&v, &x, 8);
2200+
memcpy(&u32, &y, 4);
2201+
21992202
if ((v & (1ULL << 51)) == 0) {
2200-
uint32_t u32;
2201-
memcpy(&u32, &y, 4);
22022203
u32 &= ~(1 << 22); /* make sNaN */
2203-
memcpy(&y, &u32, 4);
22042204
}
2205+
2206+
/* Workaround RISC-V: "If a NaN value is converted to a
2207+
* different floating-point type, the result is the
2208+
* canonical NaN of the new type". The canonical NaN here
2209+
* is a positive qNaN with zero payload. */
2210+
if (v & (1ULL << 63)) {
2211+
u32 |= (1 << 31); /* set sign */
2212+
}
2213+
/* add payload */
2214+
u32 -= (u32 & 0x3fffff);
2215+
u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
2216+
2217+
memcpy(&y, &u32, 4);
22052218
}
22062219

22072220
unsigned char s[sizeof(float)];

0 commit comments

Comments
 (0)