Skip to content

Commit 502589d

Browse files
committed
gh-153740: use native _Float16 in PyFloat_Pack/Unpack2
1 parent 1ec5607 commit 502589d

5 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
If available on the platform, use native :c:type:`_Float16` in
2+
:c:func:`PyFloat_Pack2` and :c:func:`PyFloat_Unpack2` functions. Patch by
3+
Sergey B Kirpichev.

Objects/floatobject.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,47 @@ _PyFloat_DebugMallocStats(FILE *out)
18941894
int
18951895
PyFloat_Pack2(double x, char *data, int le)
18961896
{
1897+
#if HAVE_FLOAT16
1898+
unsigned char *p = (unsigned char *)data;
1899+
_Float16 y = (_Float16)x;
1900+
int i, incr = 1;
1901+
1902+
if (isinf(y) && !isinf(x)) {
1903+
PyErr_SetString(PyExc_OverflowError,
1904+
"float too large to pack with e format");
1905+
return -1;
1906+
}
1907+
1908+
/* correct y if x was a sNaN, transformed to qNaN by conversion */
1909+
if (isnan(x)) {
1910+
uint64_t v;
1911+
1912+
memcpy(&v, &x, 8);
1913+
if ((v & (1ULL << 51)) == 0) {
1914+
uint16_t u16;
1915+
memcpy(&u16, &y, 2);
1916+
/* if have payload, make sNaN */
1917+
if (u16 & 0x1ff) {
1918+
u16 &= ~(1 << 9);
1919+
}
1920+
memcpy(&y, &u16, 2);
1921+
}
1922+
}
1923+
1924+
unsigned char s[sizeof(_Float16)];
1925+
memcpy(s, &y, sizeof(_Float16));
1926+
1927+
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
1928+
p += 1;
1929+
incr = -1;
1930+
}
1931+
1932+
for (i = 0; i < 2; i++) {
1933+
*p = s[i];
1934+
p += incr;
1935+
}
1936+
return 0;
1937+
#else
18971938
unsigned char *p = (unsigned char *)data;
18981939
unsigned char sign;
18991940
int e;
@@ -1997,6 +2038,7 @@ PyFloat_Pack2(double x, char *data, int le)
19972038
PyErr_SetString(PyExc_OverflowError,
19982039
"float too large to pack with e format");
19992040
return -1;
2041+
#endif /* HAVE_FLOAT16 */
20002042
}
20012043

20022044
int
@@ -2089,6 +2131,42 @@ PyFloat_Pack8(double x, char *data, int le)
20892131
double
20902132
PyFloat_Unpack2(const char *data, int le)
20912133
{
2134+
#if HAVE_FLOAT16
2135+
unsigned char *p = (unsigned char *)data;
2136+
_Float16 x;
2137+
2138+
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
2139+
char buf[2];
2140+
char *d = &buf[1];
2141+
int i;
2142+
2143+
for (i = 0; i < 2; i++) {
2144+
*d-- = *p++;
2145+
}
2146+
memcpy(&x, buf, 2);
2147+
}
2148+
else {
2149+
memcpy(&x, p, 2);
2150+
}
2151+
2152+
/* return sNaN double if x was sNaN float */
2153+
if (isnan(x)) {
2154+
uint16_t v;
2155+
2156+
memcpy(&v, &x, 2);
2157+
if ((v & (1 << 9)) == 0) {
2158+
double y = x; /* will make qNaN double */
2159+
uint64_t u64;
2160+
2161+
memcpy(&u64, &y, 8);
2162+
u64 &= ~(1ULL << 51); /* make sNaN */
2163+
memcpy(&y, &u64, 8);
2164+
return y;
2165+
}
2166+
}
2167+
2168+
return x;
2169+
#else
20922170
unsigned char *p = (unsigned char *)data;
20932171
unsigned char sign;
20942172
int e;
@@ -2140,6 +2218,7 @@ PyFloat_Unpack2(const char *data, int le)
21402218
x = -x;
21412219

21422220
return x;
2221+
#endif /* HAVE_FLOAT16 */
21432222
}
21442223

21452224
double

configure

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4457,6 +4457,22 @@ if test "$ac_cv_ffi_complex_double_supported" = "yes"; then
44574457
[Defined if _Complex C type can be used with libffi.])
44584458
fi
44594459

4460+
# Check for native half-float type.
4461+
AC_CACHE_CHECK([for _Float16 support], [ac_cv_float16_supported],
4462+
AC_RUN_IFELSE([AC_LANG_SOURCE([[
4463+
int main(void)
4464+
{
4465+
_Float16 val = 1.0f16;
4466+
return 0;
4467+
}
4468+
]])], [ac_cv_float16_supported=yes],
4469+
[ac_cv_float16_supported=no],
4470+
[ac_cv_float16_supported=no]))
4471+
if test "$ac_cv_float16_supported" = "yes"; then
4472+
AC_DEFINE([HAVE_FLOAT16], [1],
4473+
[Defined if _Float16 C type is supported])
4474+
fi
4475+
44604476
dnl Check for libmpdec >= 2.5.0
44614477
PKG_CHECK_MODULES([LIBMPDEC], [libmpdec >= 2.5.0], [have_mpdec=yes], [
44624478
WITH_SAVE_ENV([

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@
494494
/* Define if you have the 'ffi_prep_closure_loc' function. */
495495
#undef HAVE_FFI_PREP_CLOSURE_LOC
496496

497+
/* Defined if _Float16 C type is supported */
498+
#undef HAVE_FLOAT16
499+
497500
/* Define to 1 if you have the 'flock' function. */
498501
#undef HAVE_FLOCK
499502

0 commit comments

Comments
 (0)