Skip to content

Commit f16f06f

Browse files
authored
gh-133304: workaround for RISC-V in PyFloat_Pack4/Unpack4() (#133328)
1 parent 84a08f8 commit f16f06f

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
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,2 @@
1+
Workaround NaN's "canonicalization" in :c:func:`PyFloat_Pack4`
2+
and :c:func:`PyFloat_Unpack4` on RISC-V.

Objects/floatobject.c

+41
Original file line numberDiff line numberDiff line change
@@ -2196,12 +2196,33 @@ PyFloat_Pack4(double x, char *data, int le)
21962196
uint64_t v;
21972197

21982198
memcpy(&v, &x, 8);
2199+
#ifndef __riscv
21992200
if ((v & (1ULL << 51)) == 0) {
22002201
uint32_t u32;
22012202
memcpy(&u32, &y, 4);
22022203
u32 &= ~(1 << 22); /* make sNaN */
22032204
memcpy(&y, &u32, 4);
22042205
}
2206+
#else
2207+
uint32_t u32;
2208+
2209+
memcpy(&u32, &y, 4);
2210+
if ((v & (1ULL << 51)) == 0) {
2211+
u32 &= ~(1 << 22);
2212+
}
2213+
/* Workaround RISC-V: "If a NaN value is converted to a
2214+
* different floating-point type, the result is the
2215+
* canonical NaN of the new type". The canonical NaN here
2216+
* is a positive qNaN with zero payload. */
2217+
if (v & (1ULL << 63)) {
2218+
u32 |= (1 << 31); /* set sign */
2219+
}
2220+
/* add payload */
2221+
u32 -= (u32 & 0x3fffff);
2222+
u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
2223+
2224+
memcpy(&y, &u32, 4);
2225+
#endif
22052226
}
22062227

22072228
unsigned char s[sizeof(float)];
@@ -2493,6 +2514,7 @@ PyFloat_Unpack4(const char *data, int le)
24932514
uint32_t v;
24942515
memcpy(&v, &x, 4);
24952516

2517+
#ifndef __riscv
24962518
if ((v & (1 << 22)) == 0) {
24972519
double y = x; /* will make qNaN double */
24982520
uint64_t u64;
@@ -2501,6 +2523,25 @@ PyFloat_Unpack4(const char *data, int le)
25012523
memcpy(&y, &u64, 8);
25022524
return y;
25032525
}
2526+
#else
2527+
double y = x;
2528+
uint64_t u64;
2529+
2530+
memcpy(&u64, &y, 8);
2531+
if ((v & (1 << 22)) == 0) {
2532+
u64 &= ~(1ULL << 51);
2533+
}
2534+
/* Workaround RISC-V, see PyFloat_Pack4() */
2535+
if (v & (1 << 31)) {
2536+
u64 |= (1ULL << 63); /* set sign */
2537+
}
2538+
/* add payload */
2539+
u64 -= (u64 & 0x7ffffffffffffULL);
2540+
u64 += ((v & 0x3fffffULL) << 29);
2541+
2542+
memcpy(&y, &u64, 8);
2543+
return y;
2544+
#endif
25042545
}
25052546

25062547
return x;

0 commit comments

Comments
 (0)