diff options
Diffstat (limited to 'sysdeps/powerpc/fenv_libc.h')
-rw-r--r-- | sysdeps/powerpc/fenv_libc.h | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/sysdeps/powerpc/fenv_libc.h b/sysdeps/powerpc/fenv_libc.h index 45d61e1565..343be16fcb 100644 --- a/sysdeps/powerpc/fenv_libc.h +++ b/sysdeps/powerpc/fenv_libc.h @@ -22,23 +22,17 @@ #include <fenv.h> -/* Transform a logical or of the FE_* bits to a bit pattern for the - appropriate sticky bits in the FPSCR. */ -#define FE_to_sticky(excepts) \ - (-(excepts & FE_INVALID) & FE_ALL_INVALID \ - | (excepts) & (FE_ALL_EXCEPT & ~FE_INVALID | FE_ALL_INVALID)) - /* The sticky bits in the FPSCR indicating exceptions have occurred. */ #define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID) /* Equivalent to fegetenv, but returns a fenv_t instead of taking a pointer. */ #define fegetenv_register() \ - ({ fenv_t env; asm ("mffs %0" : "=f" (env)); env; }) + ({ fenv_t env; asm volatile ("mffs %0" : "=f" (env)); env; }) /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */ #define fesetenv_register(env) \ - ({ double d = (env); asm ("mtfsf 0xff,%0" : : "f" (d)); }) + ({ double d = (env); asm volatile ("mtfsf 0xff,%0" : : "f" (d)); }) /* This very handy macro: - Sets the rounding mode to 'round to nearest'; @@ -48,10 +42,65 @@ functions. */ #define relax_fenv_state() asm ("mtfsfi 7,0") +/* Set/clear a particular FPSCR bit (for instance, + reset_fpscr_bit(FPSCR_VE); + prevents INVALID exceptions from being raised). */ +#define set_fpscr_bit(x) asm volatile ("mtfsb1 %0" : : "i"(x)) +#define reset_fpscr_bit(x) asm volatile ("mtfsb0 %0" : : "i"(x)) + typedef union { fenv_t fenv; unsigned int l[2]; } fenv_union_t; +/* Definitions of all the FPSCR bit numbers */ +enum { + FPSCR_FX = 0, /* exception summary */ + FPSCR_FEX, /* enabled exception summary */ + FPSCR_VX, /* invalid operation summary */ + FPSCR_OX, /* overflow */ + FPSCR_UX, /* underflow */ + FPSCR_ZX, /* zero divide */ + FPSCR_XX, /* inexact */ + FPSCR_VXSNAN, /* invalid operation for SNaN */ + FPSCR_VXISI, /* invalid operation for Inf-Inf */ + FPSCR_VXIDI, /* invalid operation for Inf/Inf */ + FPSCR_VXZDZ, /* invalid operation for 0/0 */ + FPSCR_VXIMZ, /* invalid operation for Inf*0 */ + FPSCR_VXVC, /* invalid operation for invalid compare */ + FPSCR_FR, /* fraction rounded [fraction was incremented by round] */ + FPSCR_FI, /* fraction inexact */ + FPSCR_FPRF_C, /* result class descriptor */ + FPSCR_FPRF_FL, /* result less than (usually, less than 0) */ + FPSCR_FPRF_FG, /* result greater than */ + FPSCR_FPRF_FE, /* result equal to */ + FPSCR_FPRF_FU, /* result unordered */ + FPSCR_20, /* reserved */ + FPSCR_VXSOFT, /* invalid operation set by software */ + FPSCR_VXSQRT, /* invalid operation for square root */ + FPSCR_VXCVI, /* invalid operation for invalid integer convert */ + FPSCR_VE, /* invalid operation exception enable */ + FPSCR_OE, /* overflow exception enable */ + FPSCR_UE, /* underflow exception enable */ + FPSCR_ZE, /* zero divide exception enable */ + FPSCR_XE, /* inexact exception enable */ + FPSCR_NI /* non-IEEE mode (typically, no denormalised numbers) */ + /* the remaining two least-significant bits keep the rounding mode */ +}; + +/* This operation (i) sets the appropriate FPSCR bits for its + parameter, (ii) converts SNaN to the corresponding NaN, and (iii) + otherwise passes its parameter through unchanged (in particular, -0 + and +0 stay as they were). The `obvious' way to do this is optimised + out by gcc. */ +#define f_wash(x) \ + ({ double d; asm volatile ("fmul %0,%1,%2" \ + : "=f"(d) \ + : "f" (x), "f"((float)1.0)); d; }) +#define f_washf(x) \ + ({ float f; asm volatile ("fmuls %0,%1,%2" \ + : "=f"(f) \ + : "f" (x), "f"((float)1.0)); f; }) + #endif /* fenv_libc.h */ |