aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects/floatobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r--Objects/floatobject.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 76ed24d29fd..93e1973d6b3 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,16 +2514,34 @@ 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 */
- union double_val {
- double d;
- uint64_t u64;
- } *py = (union double_val *)&y;
-
- py->u64 &= ~(1ULL << 51); /* make sNaN */
+ uint64_t u64;
+ memcpy(&u64, &y, 8);
+ u64 &= ~(1ULL << 51); /* make sNaN */
+ 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;