void __atomic_feclearexcept (void) { unsigned int fpescr, old_fpescr; /* Get the current state. */ old_fpescr = fpescr = fegetenv_register (); /* Clear the relevant bits. */ fpescr &= ~SPEFSCR_ALL_EXCEPT; /* Put the new state in effect. */ fesetenv_register (fpescr); /* Let the kernel know if the "invalid" or "underflow" bit was cleared. */ if (old_fpescr & (SPEFSCR_FINVS | SPEFSCR_FUNFS)) { int pflags __attribute__ ((__unused__)), r; r = prctl(PR_GET_FPEXC, (unsigned long)&pflags); if (r < 0) abort (); } }
int fedisableexcept (int excepts) { int result = 0, pflags, r; INTERNAL_SYSCALL_DECL (err); r = INTERNAL_SYSCALL (prctl, err, 2, PR_GET_FPEXC, &pflags); if (INTERNAL_SYSCALL_ERROR_P (r, err)) return -1; /* Save old enable bits. */ result = __fexcepts_from_prctl (pflags); pflags &= ~__fexcepts_to_prctl (excepts); r = INTERNAL_SYSCALL (prctl, err, 2, PR_SET_FPEXC, pflags | PR_FP_EXC_SW_ENABLE); if (INTERNAL_SYSCALL_ERROR_P (r, err)) return -1; /* If disabling signals for "inexact", also disable trapping to the kernel. */ if ((excepts & FE_INEXACT) != 0) { unsigned long fpescr; fpescr = fegetenv_register (); fpescr &= ~SPEFSCR_FINXE; fesetenv_register (fpescr); } return result; }
int fedisableexcept (int excepts) { fenv_union_t fe; int result; result = fegetexcept (); if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; fe.fenv = fegetenv_register (); if (excepts & FE_INEXACT) fe.l[1] &= ~(1 << (31 - FPSCR_XE)); if (excepts & FE_DIVBYZERO) fe.l[1] &= ~(1 << (31 - FPSCR_ZE)); if (excepts & FE_UNDERFLOW) fe.l[1] &= ~(1 << (31 - FPSCR_UE)); if (excepts & FE_OVERFLOW) fe.l[1] &= ~(1 << (31 - FPSCR_OE)); if (excepts & FE_INVALID) fe.l[1] &= ~(1 << (31 - FPSCR_VE)); fesetenv_register (fe.fenv); if ((fegetexcept () & excepts) != 0) result = -1; return result; }
int __FERAISEEXCEPT_INTERNAL (int excepts) { unsigned long f; f = fegetenv_register (); f |= (excepts & SPEFSCR_ALL_EXCEPT); fesetenv_register (f); /* Force the operations that cause the exceptions. */ if ((SPEFSCR_FINVS & excepts) != 0) /* 0 / 0 */ asm volatile ("efsdiv %0,%0,%1" : : "r" (0), "r" (0)); if ((SPEFSCR_FDBZS & excepts) != 0) /* 1.0 / 0.0 */ asm volatile ("efsdiv %0,%0,%1" : : "r" (1.0F), "r" (0)); if ((SPEFSCR_FOVFS & excepts) != 0) /* Largest normalized number plus itself. */ asm volatile ("efsadd %0,%0,%1" : : "r" (0x7f7fffff), "r" (0x7f7fffff)); if ((SPEFSCR_FUNFS & excepts) != 0) /* Smallest normalized number times itself. */ asm volatile ("efsmul %0,%0,%1" : : "r" (0x800000), "r" (0x800000)); if ((SPEFSCR_FINXS & excepts) != 0) /* Smallest normalized minus 1.0 raises the inexact flag. */ asm volatile ("efssub %0,%0,%1" : : "r" (0x00800000), "r" (1.0F)); /* Success. */ return 0; }
int __feholdexcept (fenv_t *envp) { fenv_union_t u; INTERNAL_SYSCALL_DECL (err); int r; /* Get the current state. */ r = INTERNAL_SYSCALL (prctl, err, 2, PR_GET_FPEXC, &u.l[0]); if (INTERNAL_SYSCALL_ERROR_P (r, err)) return -1; u.l[1] = fegetenv_register (); *envp = u.fenv; /* Clear everything except for the rounding mode and trapping to the kernel. */ u.l[0] &= ~(PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND | PR_FP_EXC_RES | PR_FP_EXC_INV); u.l[1] &= SPEFSCR_FRMC | (SPEFSCR_ALL_EXCEPT_ENABLE & ~SPEFSCR_FINXE); /* Put the new state in effect. */ fesetenv_register (u.l[1]); r = INTERNAL_SYSCALL (prctl, err, 2, PR_SET_FPEXC, u.l[0] | PR_FP_EXC_SW_ENABLE); if (INTERNAL_SYSCALL_ERROR_P (r, err)) return -1; return 0; }
int __fesetexceptflag (const fexcept_t *flagp, int excepts) { unsigned long old_spefscr, spefscr; fexcept_t flag; int excepts_spe = __fexcepts_to_spe (excepts); /* Get the current state. */ old_spefscr = fegetenv_register (); /* Ignore exceptions not listed in 'excepts'. */ flag = *flagp & excepts_spe; /* Replace the exception status */ spefscr = (old_spefscr & ~excepts_spe) | flag; /* Store the new status word (along with the rest of the environment). */ fesetenv_register (spefscr); /* If the state of the "invalid" or "underflow" flag has changed, inform the kernel. */ if (((spefscr ^ old_spefscr) & (SPEFSCR_FINVS | SPEFSCR_FUNFS)) != 0) __fe_note_change (); /* Success. */ return 0; }
int __fegetenv (fenv_t *envp) { *envp = fegetenv_register (); /* Success. */ return 0; }
int fegetround (void) { unsigned long fpescr; fpescr = fegetenv_register (); return fpescr & 3; }
int fetestexcept (int excepts) { unsigned long f; /* Get the current state. */ f = fegetenv_register (); return __fexcepts_from_spe (f) & excepts; }
int fetestexcept (int excepts) { unsigned long f; /* Get the current state. */ f = fegetenv_register (); return f & excepts; }
int fetestexcept (int excepts) { fenv_union_t u; /* Get the current state. */ u.fenv = fegetenv_register (); /* The FE_INVALID bit is dealt with correctly by the hardware, so we can just: */ return u.l[1] & excepts; }
int __fegetenv (fenv_t *envp) { fenv_union_t u; INTERNAL_SYSCALL_DECL (err); INTERNAL_SYSCALL (prctl, err, 2, PR_GET_FPEXC, &u.l[0]); u.l[1] = fegetenv_register (); *envp = u.fenv; /* Success. */ return 0; }
int __fegetexceptflag (fexcept_t *flagp, int excepts) { unsigned long fpescr; /* Get the current state. */ fpescr = fegetenv_register (); *flagp = fpescr & SPEFSCR_ALL_EXCEPT; /* Success. */ return 0; }
int __fegetexceptflag (fexcept_t *flagp, int excepts) { fenv_union_t u; /* Get the current state. */ u.fenv = fegetenv_register (); /* Return (all of) it. */ *flagp = u.l[1] & excepts & FE_ALL_EXCEPT; /* Success. */ return 0; }
int __fegetexceptflag (fexcept_t *flagp, int excepts) { unsigned long fpescr; /* Get the current state. */ fpescr = fegetenv_register (); /* ?? Classic PPC doesn't do anything with `excepts', so we'll do the same here. (We should really be ignoring exceptions in excepts) ?? */ *flagp = fpescr & FE_ALL_EXCEPT; /* Success. */ return 0; }
int feholdexcept (fenv_t *envp) { fenv_union_t u; /* Get the current state. */ u.fenv = *envp = fegetenv_register (); /* Clear everything except for the rounding mode and non-IEEE arithmetic flag. */ u.l[1] = u.l[1] & 7; /* Put the new state in effect. */ fesetenv_register (u.fenv); return 0; }
int __FERAISEEXCEPT_INTERNAL (int excepts) { unsigned long f; f = fegetenv_register (); f |= (excepts & FE_ALL_EXCEPT); fesetenv_register (f); /* Force the operations that cause the exceptions. */ if ((FE_INVALID & excepts) != 0) { /* ?? Does not set sticky bit ?? */ /* 0 / 0 */ asm volatile ("efsdiv %0,%0,%1" : : "r" (0), "r" (0)); } if ((FE_DIVBYZERO & excepts) != 0) { /* 1.0 / 0.0 */ asm volatile ("efsdiv %0,%0,%1" : : "r" (1.0F), "r" (0)); } if ((FE_OVERFLOW & excepts) != 0) { /* ?? Does not set sticky bit ?? */ /* Largest normalized number plus itself. */ asm volatile ("efsadd %0,%0,%1" : : "r" (0x7f7fffff), "r" (0x7f7fffff)); } if ((FE_UNDERFLOW & excepts) != 0) { /* ?? Does not set sticky bit ?? */ /* Smallest normalized number times itself. */ asm volatile ("efsmul %0,%0,%1" : : "r" (0x800000), "r" (0x800000)); } if ((FE_INEXACT & excepts) != 0) { /* Smallest normalized minus 1.0 raises the inexact flag. */ asm volatile ("efssub %0,%0,%1" : : "r" (0x00800000), "r" (1.0F)); } /* Success. */ return 0; }
int __feupdateenv (const fenv_t *envp) { int exc; /* Save the currently set exceptions. */ exc = fegetenv_register () & SPEFSCR_ALL_EXCEPT; /* Install new environment. */ __fesetenv (envp); /* Raise (if appropriate) saved exceptions. */ __feraiseexcept_spe (exc); /* Success. */ return 0; }
int __flt_rounds (void) { switch (fegetenv_register () & SPEFSCR_FRMC) { case FE_TOWARDZERO: return 0; case FE_TONEAREST: return 1; case FE_UPWARD: return 2; case FE_DOWNWARD: return 3; default: abort (); } }
int feholdexcept (fenv_t *envp) { fenv_union_t u; INTERNAL_SYSCALL_DECL (err); /* Get the current state. */ INTERNAL_SYSCALL (prctl, err, 2, PR_GET_FPEXC, &u.l[0]); u.l[1] = fegetenv_register (); *envp = u.fenv; /* Clear everything except for the rounding mode. */ u.l[1] &= 3; /* Put the new state in effect. */ fesetenv_register (u.l[1]); return 0; }
int __fegetexcept (void) { fenv_union_t fe; int result = 0; fe.fenv = fegetenv_register (); if (fe.l & (1 << (31 - FPSCR_XE))) result |= FE_INEXACT; if (fe.l & (1 << (31 - FPSCR_ZE))) result |= FE_DIVBYZERO; if (fe.l & (1 << (31 - FPSCR_UE))) result |= FE_UNDERFLOW; if (fe.l & (1 << (31 - FPSCR_OE))) result |= FE_OVERFLOW; if (fe.l & (1 << (31 - FPSCR_VE))) result |= FE_INVALID; return result; }
int __feclearexcept (int excepts) { unsigned int fpescr; int excepts_spe = __fexcepts_to_spe (excepts); /* Get the current state. */ fpescr = fegetenv_register (); /* Clear the relevant bits. */ fpescr &= ~excepts_spe; /* Put the new state in effect. */ fesetenv_register (fpescr); /* Let the kernel know if the "invalid" or "underflow" bit was cleared. */ if (excepts & (FE_INVALID | FE_UNDERFLOW)) __fe_note_change (); /* Success. */ return 0; }
int __fesetexceptflag (const fexcept_t *flagp, int excepts) { unsigned long spefscr; fexcept_t flag; /* Get the current state. */ spefscr = fegetenv_register (); /* Ignore exceptions not listed in 'excepts'. */ flag = *flagp & excepts; /* Replace the exception status */ spefscr = (spefscr & ~FE_ALL_EXCEPT) | flag; /* Store the new status word (along with the rest of the environment). This may cause floating-point exceptions if the restored state requests it. */ fesetenv_register (spefscr); feraiseexcept (spefscr & FE_ALL_EXCEPT); /* Success. */ return 0; }
You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ #include <fenv_libc.h> #include <fpu_control.h> #define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM) int feholdexcept (fenv_t *envp) { fenv_union_t old, new; /* Save the currently set exceptions. */ old.fenv = *envp = fegetenv_register (); /* Clear everything except for the rounding modes and non-IEEE arithmetic flag. */ new.l = old.l & 0xffffffff00000007LL; /* If the old env had any enabled exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the FPU to run faster because it always takes the default action and can not generate SIGFPE. */ if ((old.l & _FPU_MASK_ALL) != 0) (void)__fe_mask_env (); /* Put the new state in effect. */ fesetenv_register (new.fenv); return 0;