Blame sysdeps/powerpc/fpu/fenv_libc.h

Packit 6c4009
/* Internal libc stuff for floating point environment routines.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifndef _FENV_LIBC_H
Packit 6c4009
#define _FENV_LIBC_H	1
Packit 6c4009
Packit 6c4009
#include <fenv.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
extern const fenv_t *__fe_nomask_env_priv (void);
Packit 6c4009
Packit 6c4009
extern const fenv_t *__fe_mask_env (void) attribute_hidden;
Packit 6c4009
Packit Service 1fb245
/* If the old env had any enabled exceptions and the new env has no enabled
Packit Service 1fb245
   exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
Packit Service 1fb245
   FPU to run faster because it always takes the default action and can not
Packit Service 1fb245
   generate SIGFPE.  */
Packit Service 1fb245
#define __TEST_AND_ENTER_NON_STOP(old, new) \
Packit Service 1fb245
  do { \
Packit Service 1fb245
    if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \
Packit Service 1fb245
      (void) __fe_mask_env (); \
Packit Service 1fb245
  } while (0)
Packit Service 1fb245
Packit Service 1fb245
/* If the old env has no enabled exceptions and the new env has any enabled
Packit Service 1fb245
   exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
Packit Service 1fb245
   hardware into "precise mode" and may cause the FPU to run slower on some
Packit Service 1fb245
   hardware.  */
Packit Service 1fb245
#define __TEST_AND_EXIT_NON_STOP(old, new) \
Packit Service 1fb245
  do { \
Packit Service 1fb245
    if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \
Packit Service 1fb245
      (void) __fe_nomask_env_priv (); \
Packit Service 1fb245
  } while (0)
Packit Service 1fb245
Packit 6c4009
/* The sticky bits in the FPSCR indicating exceptions have occurred.  */
Packit 6c4009
#define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID)
Packit 6c4009
Packit 6c4009
/* Equivalent to fegetenv, but returns a fenv_t instead of taking a
Packit 6c4009
   pointer.  */
Packit 6c4009
#define fegetenv_register() \
Packit 6c4009
        ({ fenv_t env; asm volatile ("mffs %0" : "=f" (env)); env; })
Packit 6c4009
Packit Service 78b984
/* Equivalent to fegetenv_register, but only returns bits for
Packit Service 4b47da
   status, exception enables, and mode.
Packit Service 4b47da
   Nicely, it turns out that the 'mffsl' instruction will decode to
Packit Service 4b47da
   'mffs' on architectures older than "power9" because the additional
Packit Service 4b47da
   bits set for 'mffsl' are "don't care" for 'mffs'.  'mffs' is a superset
Packit Service 4b47da
   of 'mffsl'.  */
Packit Service 5eaca1
#define fegetenv_control()					\
Packit Service 78b984
  ({register double __fr;						\
Packit Service 78b984
    __asm__ __volatile__ (						\
Packit Service 78b984
      ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
Packit Service 78b984
      : "=f" (__fr));							\
Packit Service 78b984
    __fr;								\
Packit Service 78b984
  })
Packit Service 78b984
Packit Service 3e5c07
#define __fe_mffscrn(rn)						\
Packit Service 3e5c07
  ({register fenv_union_t __fr;						\
Packit Service 3e5c07
    if (__builtin_constant_p (rn))					\
Packit Service 3e5c07
      __asm__ __volatile__ (						\
Packit Service 3e5c07
        ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
Packit Service 3e5c07
        : "=f" (__fr.fenv) : "i" (rn));					\
Packit Service 3e5c07
    else								\
Packit Service 3e5c07
    {									\
Packit Service 3e5c07
      __fr.l = (rn);							\
Packit Service 3e5c07
      __asm__ __volatile__ (						\
Packit Service 3e5c07
        ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
Packit Service 3e5c07
        : "=f" (__fr.fenv) : "f" (__fr.fenv));				\
Packit Service 3e5c07
    }									\
Packit Service 3e5c07
    __fr.fenv;								\
Packit Service 3e5c07
  })
Packit Service 3e5c07
Packit Service 5eaca1
/* Like fegetenv_control, but also sets the rounding mode.  */
Packit Service 3e5c07
#ifdef _ARCH_PWR9
Packit Service 3e5c07
#define fegetenv_and_set_rn(rn) __fe_mffscrn (rn)
Packit Service 3e5c07
#else
Packit Service 3e5c07
/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
Packit Service 3e5c07
   but not sufficient, because it does not set the rounding mode.
Packit Service 3e5c07
   Explicitly set the rounding mode when 'mffscrn' actually doesn't.  */
Packit Service 3e5c07
#define fegetenv_and_set_rn(rn)						\
Packit Service 3e5c07
  ({register fenv_union_t __fr;						\
Packit Service 3e5c07
    __fr.fenv = __fe_mffscrn (rn);					\
Packit Service 3e5c07
    if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)))	\
Packit Service 3e5c07
      __fesetround_inline (rn);						\
Packit Service 3e5c07
    __fr.fenv;								\
Packit Service 3e5c07
  })
Packit Service 3e5c07
#endif
Packit Service 3e5c07
Packit 6c4009
/* Equivalent to fesetenv, but takes a fenv_t instead of a pointer.  */
Packit 6c4009
#define fesetenv_register(env) \
Packit 6c4009
	do { \
Packit 6c4009
	  double d = (env); \
Packit 6c4009
	  if(GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
Packit 6c4009
	    asm volatile (".machine push; " \
Packit 6c4009
			  ".machine \"power6\"; " \
Packit 6c4009
			  "mtfsf 0xff,%0,1,0; " \
Packit 6c4009
			  ".machine pop" : : "f" (d)); \
Packit 6c4009
	  else \
Packit 6c4009
	    asm volatile ("mtfsf 0xff,%0" : : "f" (d)); \
Packit 6c4009
	} while(0)
Packit 6c4009
Packit Service 41c03e
/* Set the last 2 nibbles of the FPSCR, which contain the
Packit Service 41c03e
   exception enables and the rounding mode.
Packit Service 5eaca1
   'fegetenv_control' retrieves these bits by reading the FPSCR.  */
Packit Service 41c03e
#define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env));
Packit Service 41c03e
Packit 6c4009
/* This very handy macro:
Packit 6c4009
   - Sets the rounding mode to 'round to nearest';
Packit 6c4009
   - Sets the processor into IEEE mode; and
Packit 6c4009
   - Prevents exceptions from being raised for inexact results.
Packit 6c4009
   These things happen to be exactly what you need for typical elementary
Packit 6c4009
   functions.  */
Packit 6c4009
#define relax_fenv_state() \
Packit 6c4009
	do { \
Packit 6c4009
	   if (GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
Packit Service 2f961d
	     asm volatile (".machine push; .machine \"power6\"; " \
Packit 6c4009
		  "mtfsfi 7,0,1; .machine pop"); \
Packit Service 2f961d
	   asm volatile ("mtfsfi 7,0"); \
Packit 6c4009
	} while(0)
Packit 6c4009
Packit 6c4009
/* Set/clear a particular FPSCR bit (for instance,
Packit 6c4009
   reset_fpscr_bit(FPSCR_VE);
Packit 6c4009
   prevents INVALID exceptions from being raised).  */
Packit 6c4009
#define set_fpscr_bit(x) asm volatile ("mtfsb1 %0" : : "i"(x))
Packit 6c4009
#define reset_fpscr_bit(x) asm volatile ("mtfsb0 %0" : : "i"(x))
Packit 6c4009
Packit 6c4009
typedef union
Packit 6c4009
{
Packit 6c4009
  fenv_t fenv;
Packit 6c4009
  unsigned long long l;
Packit 6c4009
} fenv_union_t;
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__fesetround_inline (int round)
Packit 6c4009
{
Packit Service 8858d6
#ifdef _ARCH_PWR9
Packit Service 8858d6
  __fe_mffscrn (round);
Packit Service 8858d6
#else
Packit Service 8858d6
  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
Packit Service 8858d6
    __fe_mffscrn (round);
Packit Service 8858d6
  else if ((unsigned int) round < 2)
Packit 6c4009
    {
Packit 6c4009
       asm volatile ("mtfsb0 30");
Packit 6c4009
       if ((unsigned int) round == 0)
Packit 6c4009
         asm volatile ("mtfsb0 31");
Packit 6c4009
       else
Packit 6c4009
         asm volatile ("mtfsb1 31");
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
       asm volatile ("mtfsb1 30");
Packit 6c4009
       if ((unsigned int) round == 2)
Packit 6c4009
         asm volatile ("mtfsb0 31");
Packit 6c4009
       else
Packit 6c4009
         asm volatile ("mtfsb1 31");
Packit 6c4009
    }
Packit Service 8858d6
#endif
Packit Service 93dc7a
  return 0;
Packit edaf47
}
Packit edaf47
Packit Service a34558
/* Same as __fesetround_inline, however without runtime check to use DFP
Packit Service a34558
   mtfsfi syntax (as relax_fenv_state) or if round value is valid.  */
Packit Service a34558
static inline void
Packit Service a34558
__fesetround_inline_nocheck (const int round)
Packit Service a34558
{
Packit Service 8858d6
#ifdef _ARCH_PWR9
Packit Service 8858d6
  __fe_mffscrn (round);
Packit Service 8858d6
#else
Packit Service 8858d6
  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
Packit Service 8858d6
    __fe_mffscrn (round);
Packit Service 8858d6
  else
Packit Service 8858d6
    asm volatile ("mtfsfi 7,%0" : : "i" (round));
Packit Service 8858d6
#endif
Packit Service a34558
}
Packit Service a34558
Packit Service 0c3164
#define FPSCR_MASK(bit) (1 << (31 - (bit)))
Packit Service 0c3164
Packit 6c4009
/* Definitions of all the FPSCR bit numbers */
Packit 6c4009
enum {
Packit 6c4009
  FPSCR_FX = 0,    /* exception summary */
Packit Service 0c3164
#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
Packit 6c4009
  FPSCR_FEX,       /* enabled exception summary */
Packit Service 0c3164
#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
Packit 6c4009
  FPSCR_VX,        /* invalid operation summary */
Packit Service 0c3164
#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
Packit 6c4009
  FPSCR_OX,        /* overflow */
Packit Service 0c3164
#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
Packit 6c4009
  FPSCR_UX,        /* underflow */
Packit Service 0c3164
#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
Packit 6c4009
  FPSCR_ZX,        /* zero divide */
Packit Service 0c3164
#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
Packit 6c4009
  FPSCR_XX,        /* inexact */
Packit Service 0c3164
#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
Packit 6c4009
  FPSCR_VXSNAN,    /* invalid operation for sNaN */
Packit Service 0c3164
#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
Packit 6c4009
  FPSCR_VXISI,     /* invalid operation for Inf-Inf */
Packit Service 0c3164
#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
Packit 6c4009
  FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
Packit Service 0c3164
#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
Packit 6c4009
  FPSCR_VXZDZ,     /* invalid operation for 0/0 */
Packit Service 0c3164
#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
Packit 6c4009
  FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
Packit Service 0c3164
#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
Packit 6c4009
  FPSCR_VXVC,      /* invalid operation for invalid compare */
Packit Service 0c3164
#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
Packit 6c4009
  FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
Packit Service 0c3164
#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
Packit 6c4009
  FPSCR_FI,        /* fraction inexact */
Packit Service 0c3164
#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
Packit 6c4009
  FPSCR_FPRF_C,    /* result class descriptor */
Packit Service 0c3164
#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
Packit 6c4009
  FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
Packit Service 0c3164
#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
Packit 6c4009
  FPSCR_FPRF_FG,   /* result greater than */
Packit Service 0c3164
#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
Packit 6c4009
  FPSCR_FPRF_FE,   /* result equal to */
Packit Service 0c3164
#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
Packit 6c4009
  FPSCR_FPRF_FU,   /* result unordered */
Packit Service 0c3164
#define FPSCR_FPRF_FU_MASK (FPSCR_MASK (FPSCR_FPRF_FU))
Packit 6c4009
  FPSCR_20,        /* reserved */
Packit 6c4009
  FPSCR_VXSOFT,    /* invalid operation set by software */
Packit Service 0c3164
#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
Packit 6c4009
  FPSCR_VXSQRT,    /* invalid operation for square root */
Packit Service 0c3164
#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
Packit 6c4009
  FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
Packit Service 0c3164
#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
Packit 6c4009
  FPSCR_VE,        /* invalid operation exception enable */
Packit Service 0c3164
#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
Packit 6c4009
  FPSCR_OE,        /* overflow exception enable */
Packit Service 0c3164
#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
Packit 6c4009
  FPSCR_UE,        /* underflow exception enable */
Packit Service 0c3164
#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
Packit 6c4009
  FPSCR_ZE,        /* zero divide exception enable */
Packit Service 0c3164
#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
Packit 6c4009
  FPSCR_XE,        /* inexact exception enable */
Packit Service 0c3164
#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
Packit 6c4009
#ifdef _ARCH_PWR6
Packit 6c4009
  FPSCR_29,        /* Reserved in ISA 2.05  */
Packit Service 0c3164
#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
Packit 6c4009
#else
Packit Service 0c3164
  FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
Packit Service 0c3164
#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_NI))
Packit 6c4009
#endif /* _ARCH_PWR6 */
Packit 6c4009
  /* the remaining two least-significant bits keep the rounding mode */
Packit Service 0c3164
  FPSCR_RN_hi,
Packit Service 0c3164
#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
Packit Service 0c3164
  FPSCR_RN_lo
Packit Service 0c3164
#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
Packit 6c4009
};
Packit 6c4009
Packit Service 0c3164
#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
Packit Service 0c3164
#define FPSCR_ENABLES_MASK \
Packit Service 0c3164
  (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
Packit Service 0c3164
#define FPSCR_BASIC_EXCEPTIONS_MASK \
Packit Service 0c3164
  (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
Packit Service 269c14
#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
Packit Service 269c14
  FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
Packit Service 269c14
  FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
Packit Service 269c14
  FPSCR_VXCVI_MASK)
Packit Service 41c03e
#define FPSCR_FPRF_MASK \
Packit Service 41c03e
  (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
Packit Service 41c03e
   FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
Packit Service 0c3164
#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
Packit Service 41c03e
#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
Packit Service 0c3164
Packit Service 0c3164
/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
Packit Service 0c3164
   in the FPSCR, albeit shifted to different but corresponding locations.
Packit Service 0c3164
   Similarly, the exception indicator bits in the FPSCR correspond one-to-one
Packit Service 0c3164
   with the exception enable bits. It is thus possible to map the FENV(1)
Packit Service 0c3164
   exceptions directly to the FPSCR enables with a simple mask and shift,
Packit Service 0c3164
   and vice versa. */
Packit Service 0c3164
#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
Packit Service 0c3164
Packit 6c4009
static inline int
Packit 6c4009
fenv_reg_to_exceptions (unsigned long long l)
Packit 6c4009
{
Packit Service 0c3164
  return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
Packit Service 0c3164
}
Packit Service 0c3164
Packit Service 0c3164
static inline unsigned long long
Packit Service 0c3164
fenv_exceptions_to_reg (int excepts)
Packit Service 0c3164
{
Packit Service 0c3164
  return (unsigned long long)
Packit Service 0c3164
    (excepts & FE_ALL_EXCEPT) >> FPSCR_EXCEPT_TO_ENABLE_SHIFT;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef _ARCH_PWR6
Packit 6c4009
  /* Not supported in ISA 2.05.  Provided for source compat only.  */
Packit 6c4009
# define FPSCR_NI 29
Packit 6c4009
#endif /* _ARCH_PWR6 */
Packit 6c4009
Packit 6c4009
/* This operation (i) sets the appropriate FPSCR bits for its
Packit 6c4009
   parameter, (ii) converts sNaN to the corresponding qNaN, and (iii)
Packit 6c4009
   otherwise passes its parameter through unchanged (in particular, -0
Packit 6c4009
   and +0 stay as they were).  The `obvious' way to do this is optimised
Packit 6c4009
   out by gcc.  */
Packit 6c4009
#define f_wash(x) \
Packit 6c4009
   ({ double d; asm volatile ("fmul %0,%1,%2" \
Packit 6c4009
			      : "=f"(d) \
Packit 6c4009
			      : "f" (x), "f"((float)1.0)); d; })
Packit 6c4009
#define f_washf(x) \
Packit 6c4009
   ({ float f; asm volatile ("fmuls %0,%1,%2" \
Packit 6c4009
			     : "=f"(f) \
Packit 6c4009
			     : "f" (x), "f"((float)1.0)); f; })
Packit 6c4009
Packit 6c4009
#endif /* fenv_libc.h */