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 97ab7f
/* If the old env had any enabled exceptions and the new env has no enabled
Packit Service 97ab7f
   exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
Packit Service 97ab7f
   FPU to run faster because it always takes the default action and can not
Packit Service 97ab7f
   generate SIGFPE.  */
Packit Service 97ab7f
#define __TEST_AND_ENTER_NON_STOP(old, new) \
Packit Service 97ab7f
  do { \
Packit Service 97ab7f
    if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \
Packit Service 97ab7f
      (void) __fe_mask_env (); \
Packit Service 97ab7f
  } while (0)
Packit Service 97ab7f
Packit Service 97ab7f
/* If the old env has no enabled exceptions and the new env has any enabled
Packit Service 97ab7f
   exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
Packit Service 97ab7f
   hardware into "precise mode" and may cause the FPU to run slower on some
Packit Service 97ab7f
   hardware.  */
Packit Service 97ab7f
#define __TEST_AND_EXIT_NON_STOP(old, new) \
Packit Service 97ab7f
  do { \
Packit Service 97ab7f
    if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \
Packit Service 97ab7f
      (void) __fe_nomask_env_priv (); \
Packit Service 97ab7f
  } while (0)
Packit Service 97ab7f
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 da74a7
/* Equivalent to fegetenv_register, but only returns bits for
Packit Service 81ddd8
   status, exception enables, and mode.
Packit Service 81ddd8
   Nicely, it turns out that the 'mffsl' instruction will decode to
Packit Service 81ddd8
   'mffs' on architectures older than "power9" because the additional
Packit Service 81ddd8
   bits set for 'mffsl' are "don't care" for 'mffs'.  'mffs' is a superset
Packit Service 81ddd8
   of 'mffsl'.  */
Packit Service 81ddd8
#define fegetenv_status()					\
Packit Service da74a7
  ({register double __fr;						\
Packit Service da74a7
    __asm__ __volatile__ (						\
Packit Service da74a7
      ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
Packit Service da74a7
      : "=f" (__fr));							\
Packit Service da74a7
    __fr;								\
Packit Service da74a7
  })
Packit Service da74a7
Packit Service 4027bc
#define __fe_mffscrn(rn)						\
Packit Service 4027bc
  ({register fenv_union_t __fr;						\
Packit Service 4027bc
    if (__builtin_constant_p (rn))					\
Packit Service 4027bc
      __asm__ __volatile__ (						\
Packit Service 4027bc
        ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
Packit Service 4027bc
        : "=f" (__fr.fenv) : "i" (rn));					\
Packit Service 4027bc
    else								\
Packit Service 4027bc
    {									\
Packit Service 4027bc
      __fr.l = (rn);							\
Packit Service 4027bc
      __asm__ __volatile__ (						\
Packit Service 4027bc
        ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
Packit Service 4027bc
        : "=f" (__fr.fenv) : "f" (__fr.fenv));				\
Packit Service 4027bc
    }									\
Packit Service 4027bc
    __fr.fenv;								\
Packit Service 4027bc
  })
Packit Service 4027bc
Packit Service 4027bc
/* Like fegetenv_status, but also sets the rounding mode.  */
Packit Service 4027bc
#ifdef _ARCH_PWR9
Packit Service 4027bc
#define fegetenv_and_set_rn(rn) __fe_mffscrn (rn)
Packit Service 4027bc
#else
Packit Service 4027bc
/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
Packit Service 4027bc
   but not sufficient, because it does not set the rounding mode.
Packit Service 4027bc
   Explicitly set the rounding mode when 'mffscrn' actually doesn't.  */
Packit Service 4027bc
#define fegetenv_and_set_rn(rn)						\
Packit Service 4027bc
  ({register fenv_union_t __fr;						\
Packit Service 4027bc
    __fr.fenv = __fe_mffscrn (rn);					\
Packit Service 4027bc
    if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)))	\
Packit Service 4027bc
      __fesetround_inline (rn);						\
Packit Service 4027bc
    __fr.fenv;								\
Packit Service 4027bc
  })
Packit Service 4027bc
#endif
Packit Service 4027bc
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 f12392
/* Set the last 2 nibbles of the FPSCR, which contain the
Packit Service f12392
   exception enables and the rounding mode.
Packit Service f12392
   'fegetenv_status' retrieves these bits by reading the FPSCR.  */
Packit Service f12392
#define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env));
Packit Service f12392
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 9dab1a
	     asm volatile (".machine push; .machine \"power6\"; " \
Packit 6c4009
		  "mtfsfi 7,0,1; .machine pop"); \
Packit Service 9dab1a
	   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 771895
#ifdef _ARCH_PWR9
Packit Service 771895
  __fe_mffscrn (round);
Packit Service 771895
#else
Packit Service 771895
  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
Packit Service 771895
    __fe_mffscrn (round);
Packit Service 771895
  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 771895
#endif
Packit Service 8bbac7
  return 0;
Packit Service cbfc86
}
Packit Service cbfc86
Packit Service 425722
/* Same as __fesetround_inline, however without runtime check to use DFP
Packit Service 425722
   mtfsfi syntax (as relax_fenv_state) or if round value is valid.  */
Packit Service 425722
static inline void
Packit Service 425722
__fesetround_inline_nocheck (const int round)
Packit Service 425722
{
Packit Service 771895
#ifdef _ARCH_PWR9
Packit Service 771895
  __fe_mffscrn (round);
Packit Service 771895
#else
Packit Service 771895
  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
Packit Service 771895
    __fe_mffscrn (round);
Packit Service 771895
  else
Packit Service 771895
    asm volatile ("mtfsfi 7,%0" : : "i" (round));
Packit Service 771895
#endif
Packit Service 425722
}
Packit Service 425722
Packit Service 42e4aa
#define FPSCR_MASK(bit) (1 << (31 - (bit)))
Packit Service 42e4aa
Packit 6c4009
/* Definitions of all the FPSCR bit numbers */
Packit 6c4009
enum {
Packit 6c4009
  FPSCR_FX = 0,    /* exception summary */
Packit Service 42e4aa
#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
Packit 6c4009
  FPSCR_FEX,       /* enabled exception summary */
Packit Service 42e4aa
#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
Packit 6c4009
  FPSCR_VX,        /* invalid operation summary */
Packit Service 42e4aa
#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
Packit 6c4009
  FPSCR_OX,        /* overflow */
Packit Service 42e4aa
#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
Packit 6c4009
  FPSCR_UX,        /* underflow */
Packit Service 42e4aa
#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
Packit 6c4009
  FPSCR_ZX,        /* zero divide */
Packit Service 42e4aa
#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
Packit 6c4009
  FPSCR_XX,        /* inexact */
Packit Service 42e4aa
#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
Packit 6c4009
  FPSCR_VXSNAN,    /* invalid operation for sNaN */
Packit Service 42e4aa
#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
Packit 6c4009
  FPSCR_VXISI,     /* invalid operation for Inf-Inf */
Packit Service 42e4aa
#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
Packit 6c4009
  FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
Packit Service 42e4aa
#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
Packit 6c4009
  FPSCR_VXZDZ,     /* invalid operation for 0/0 */
Packit Service 42e4aa
#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
Packit 6c4009
  FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
Packit Service 42e4aa
#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
Packit 6c4009
  FPSCR_VXVC,      /* invalid operation for invalid compare */
Packit Service 42e4aa
#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
Packit 6c4009
  FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
Packit Service 42e4aa
#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
Packit 6c4009
  FPSCR_FI,        /* fraction inexact */
Packit Service 42e4aa
#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
Packit 6c4009
  FPSCR_FPRF_C,    /* result class descriptor */
Packit Service 42e4aa
#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
Packit 6c4009
  FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
Packit Service 42e4aa
#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
Packit 6c4009
  FPSCR_FPRF_FG,   /* result greater than */
Packit Service 42e4aa
#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
Packit 6c4009
  FPSCR_FPRF_FE,   /* result equal to */
Packit Service 42e4aa
#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
Packit 6c4009
  FPSCR_FPRF_FU,   /* result unordered */
Packit Service 42e4aa
#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 42e4aa
#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
Packit 6c4009
  FPSCR_VXSQRT,    /* invalid operation for square root */
Packit Service 42e4aa
#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
Packit 6c4009
  FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
Packit Service 42e4aa
#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
Packit 6c4009
  FPSCR_VE,        /* invalid operation exception enable */
Packit Service 42e4aa
#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
Packit 6c4009
  FPSCR_OE,        /* overflow exception enable */
Packit Service 42e4aa
#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
Packit 6c4009
  FPSCR_UE,        /* underflow exception enable */
Packit Service 42e4aa
#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
Packit 6c4009
  FPSCR_ZE,        /* zero divide exception enable */
Packit Service 42e4aa
#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
Packit 6c4009
  FPSCR_XE,        /* inexact exception enable */
Packit Service 42e4aa
#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
Packit 6c4009
#ifdef _ARCH_PWR6
Packit 6c4009
  FPSCR_29,        /* Reserved in ISA 2.05  */
Packit Service 42e4aa
#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
Packit 6c4009
#else
Packit Service 42e4aa
  FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
Packit Service 42e4aa
#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 42e4aa
  FPSCR_RN_hi,
Packit Service 42e4aa
#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
Packit Service 42e4aa
  FPSCR_RN_lo
Packit Service 42e4aa
#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
Packit 6c4009
};
Packit 6c4009
Packit Service 42e4aa
#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
Packit Service 42e4aa
#define FPSCR_ENABLES_MASK \
Packit Service 42e4aa
  (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
Packit Service 42e4aa
#define FPSCR_BASIC_EXCEPTIONS_MASK \
Packit Service 42e4aa
  (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
Packit Service 9fe962
#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
Packit Service 9fe962
  FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
Packit Service 9fe962
  FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
Packit Service 9fe962
  FPSCR_VXCVI_MASK)
Packit Service f12392
#define FPSCR_FPRF_MASK \
Packit Service f12392
  (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
Packit Service f12392
   FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
Packit Service 42e4aa
#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
Packit Service f12392
#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
Packit Service 42e4aa
Packit Service 42e4aa
/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
Packit Service 42e4aa
   in the FPSCR, albeit shifted to different but corresponding locations.
Packit Service 42e4aa
   Similarly, the exception indicator bits in the FPSCR correspond one-to-one
Packit Service 42e4aa
   with the exception enable bits. It is thus possible to map the FENV(1)
Packit Service 42e4aa
   exceptions directly to the FPSCR enables with a simple mask and shift,
Packit Service 42e4aa
   and vice versa. */
Packit Service 42e4aa
#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
Packit Service 42e4aa
Packit 6c4009
static inline int
Packit 6c4009
fenv_reg_to_exceptions (unsigned long long l)
Packit 6c4009
{
Packit Service 42e4aa
  return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
Packit Service 42e4aa
}
Packit Service 42e4aa
Packit Service 42e4aa
static inline unsigned long long
Packit Service 42e4aa
fenv_exceptions_to_reg (int excepts)
Packit Service 42e4aa
{
Packit Service 42e4aa
  return (unsigned long long)
Packit Service 42e4aa
    (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 */