diff --git a/lib/msun/powerpc/fenv.h b/lib/msun/powerpc/fenv.h --- a/lib/msun/powerpc/fenv.h +++ b/lib/msun/powerpc/fenv.h @@ -42,6 +42,17 @@ typedef __uint32_t fexcept_t; /* Exception flags */ +#ifdef __SPE__ +#define FE_OVERFLOW 0x00000100 +#define FE_UNDERFLOW 0x00000200 +#define FE_DIVBYZERO 0x00000400 +#define FE_INVALID 0x00000800 +#define FE_INEXACT 0x00001000 + +#define FE_ALL_INVALID FE_INVALID + +#define _FPUSW_SHIFT 6 +#else #define FE_INEXACT 0x02000000 #define FE_DIVBYZERO 0x04000000 #define FE_UNDERFLOW 0x08000000 @@ -67,6 +78,9 @@ #define FE_ALL_INVALID (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \ FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \ FE_VXSNAN | FE_INVALID) + +#define _FPUSW_SHIFT 22 +#endif #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW) @@ -85,7 +99,6 @@ #define FE_DFL_ENV (&__fe_dfl_env) /* We need to be able to map status flag positions to mask flag positions */ -#define _FPUSW_SHIFT 22 #define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT) @@ -156,6 +169,9 @@ return (0); } +#ifdef __SPE__ +extern int feraiseexcept(int __excepts); +#else __fenv_static inline int feraiseexcept(int __excepts) { @@ -168,6 +184,7 @@ __mtfsf(__r); return (0); } +#endif __fenv_static inline int fetestexcept(int __excepts) diff --git a/lib/msun/powerpc/fenv.c b/lib/msun/powerpc/fenv.c --- a/lib/msun/powerpc/fenv.c +++ b/lib/msun/powerpc/fenv.c @@ -30,6 +30,10 @@ #define __fenv_static #include "fenv.h" +#ifdef __SPE__ +#include +#include +#endif #ifdef __GNUC_GNU_INLINE__ #error "This file must be compiled with C99 'inline' semantics" @@ -40,7 +44,9 @@ extern inline int feclearexcept(int __excepts); extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +#ifndef __SPE__ extern inline int feraiseexcept(int __excepts); +#endif extern inline int fetestexcept(int __excepts); extern inline int fegetround(void); extern inline int fesetround(int __round); @@ -48,3 +54,27 @@ extern inline int feholdexcept(fenv_t *__envp); extern inline int fesetenv(const fenv_t *__envp); extern inline int feupdateenv(const fenv_t *__envp); + +#ifdef __SPE__ +#define PMAX 0x7f7fffff +#define PMIN 0x00800000 +int feraiseexcept(int __excepts) +{ + uint32_t spefscr; + + spefscr = mfspr(SPR_SPEFSCR); + mtspr(SPR_SPEFSCR, spefscr | (__excepts & FE_ALL_EXCEPT)); + + if (__excepts & FE_INVALID) + __asm __volatile ("efsdiv %0, %0, %1" :: "r"(0), "r"(0)); + if (__excepts & FE_DIVBYZERO) + __asm __volatile ("efsdiv %0, %0, %1" :: "r"(1.0f), "r"(0)); + if (__excepts & FE_UNDERFLOW) + __asm __volatile ("efsmul %0, %0, %0" :: "r"(PMIN)); + if (__excepts & FE_OVERFLOW) + __asm __volatile ("efsadd %0, %0, %0" :: "r"(PMAX)); + if (__excepts & FE_INEXACT) + __asm __volatile ("efssub %0, %0, %1" :: "r"(PMIN), "r"(1.0f)); + return (0); +} +#endif