From 96e53641b0dd61ea9ce1749392c184d875c19359 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Sat, 11 Jun 2022 11:19:42 -0700 Subject: [PATCH 1/3] ENH: Add support for platforms with missing fenv flags For instance wasm has no fenv support. musl-libc defines all the fenv functions unconditionally (fesetexcept, feclearexcept, etc) but on unsupported platforms they are no-ops: https://git.musl-libc.org/cgit/musl/tree/src/fenv/fenv.c However, the platform is expected to only define flags like FE_OVERFLOW if they are supported. I haven't found an explanation of the design decision, but it seems to be aimed at fine-grained feature detection. musl-libc-test has code that uses fenv and wants it to silently decay to a no-op on platforms missing support. I copied their implementation of this behavior: http://nsz.repo.hu/git/?p=libc-test;a=blob;f=src/common/mtest.h;h=706c1ba23ea8989b17a2f72ed1a919e187c06b6a;hb=HEAD#l30 --- numpy/core/src/npymath/ieee754.c.src | 67 ++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/numpy/core/src/npymath/ieee754.c.src b/numpy/core/src/npymath/ieee754.c.src index 4e6ddb712..fc4692735 100644 --- a/numpy/core/src/npymath/ieee754.c.src +++ b/numpy/core/src/npymath/ieee754.c.src @@ -789,10 +789,52 @@ int npy_clear_floatstatus_barrier(char *param) /* General GCC code, should work on most platforms */ # include +// musl-libc defines all the fenv functions unconditionally (fesetexcept, +// feclearexcept, etc) but on unsupported platforms they are no-ops: +// https://git.musl-libc.org/cgit/musl/tree/src/fenv/fenv.c +// However, the platform is expected to only define flags like +// FE_OVERFLOW if they are supported. I haven't found an explanation +// of the design decision, but it seems to be aimed at fine-grained +// feature detection. musl-libc-test has code that uses fenv and wants +// it to silently decay to a no-op on platforms missing support. I +// copied their implementation of this behavior: +// http://nsz.repo.hu/git/?p=libc-test;a=blob;f=src/common/mtest.h;h=706c1ba23ea8989b17a2f72ed1a919e187c06b6a;hb=HEAD#l30 +#undef INEXACT +#undef INVALID +#undef DIVBYZERO +#undef UNDERFLOW +#undef OVERFLOW +#ifdef FE_INEXACT +#define INEXACT FE_INEXACT +#else +#define INEXACT 0 +#endif +#ifdef FE_INVALID +#define INVALID FE_INVALID +#else +#define INVALID 0 +#endif +#ifdef FE_DIVBYZERO +#define DIVBYZERO FE_DIVBYZERO +#else +#define DIVBYZERO 0 +#endif +#ifdef FE_UNDERFLOW +#define UNDERFLOW FE_UNDERFLOW +#else +#define UNDERFLOW 0 +#endif +#ifdef FE_OVERFLOW +#define OVERFLOW FE_OVERFLOW +#else +#define OVERFLOW 0 +#endif + + int npy_get_floatstatus_barrier(char* param) { - int fpstatus = fetestexcept(FE_DIVBYZERO | FE_OVERFLOW | - FE_UNDERFLOW | FE_INVALID); + int fpstatus = fetestexcept(DIVBYZERO | OVERFLOW | + UNDERFLOW | INVALID); /* * By using a volatile, the compiler cannot reorder this call */ @@ -800,10 +842,10 @@ int npy_get_floatstatus_barrier(char* param) volatile char NPY_UNUSED(c) = *(char*)param; } - return ((FE_DIVBYZERO & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | - ((FE_OVERFLOW & fpstatus) ? NPY_FPE_OVERFLOW : 0) | - ((FE_UNDERFLOW & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | - ((FE_INVALID & fpstatus) ? NPY_FPE_INVALID : 0); + return ((DIVBYZERO & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((OVERFLOW & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((UNDERFLOW & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((INVALID & fpstatus) ? NPY_FPE_INVALID : 0); } int npy_clear_floatstatus_barrier(char * param) @@ -811,8 +853,8 @@ int npy_clear_floatstatus_barrier(char * param) /* testing float status is 50-100 times faster than clearing on x86 */ int fpstatus = npy_get_floatstatus_barrier(param); if (fpstatus != 0) { - feclearexcept(FE_DIVBYZERO | FE_OVERFLOW | - FE_UNDERFLOW | FE_INVALID); + feclearexcept(DIVBYZERO | OVERFLOW | + UNDERFLOW | INVALID); } return fpstatus; @@ -821,22 +863,21 @@ int npy_clear_floatstatus_barrier(char * param) void npy_set_floatstatus_divbyzero(void) { - feraiseexcept(FE_DIVBYZERO); + feraiseexcept(DIVBYZERO); } void npy_set_floatstatus_overflow(void) { - feraiseexcept(FE_OVERFLOW); + feraiseexcept(OVERFLOW); } void npy_set_floatstatus_underflow(void) { - feraiseexcept(FE_UNDERFLOW); + feraiseexcept(UNDERFLOW); } void npy_set_floatstatus_invalid(void) { - feraiseexcept(FE_INVALID); + feraiseexcept(INVALID); } - #endif -- 2.25.1