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 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 ff6bf9
/* Equivalent to fegetenv_register, but only returns bits for
Packit ff6bf9
   status, exception enables, and mode.  */
Packit ff6bf9
Packit ff6bf9
#define fegetenv_status_ISA300()					\
Packit ff6bf9
  ({register double __fr;						\
Packit ff6bf9
    __asm__ __volatile__ (						\
Packit ff6bf9
      ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
Packit ff6bf9
      : "=f" (__fr));							\
Packit ff6bf9
    __fr;								\
Packit ff6bf9
  })
Packit ff6bf9
Packit ff6bf9
#ifdef _ARCH_PWR9
Packit ff6bf9
# define fegetenv_status() fegetenv_status_ISA300()
Packit 5bb8dd
#elif defined __BUILTIN_CPU_SUPPORTS__
Packit ff6bf9
# define fegetenv_status()						\
Packit ff6bf9
  (__glibc_likely (__builtin_cpu_supports ("arch_3_00"))		\
Packit ff6bf9
   ? fegetenv_status_ISA300()						\
Packit ff6bf9
   : fegetenv_register()						\
Packit ff6bf9
  )
Packit 5bb8dd
#else
Packit 5bb8dd
# define fegetenv_status() fegetenv_register ()
Packit ff6bf9
#endif
Packit ff6bf9
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 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 363171
	     asm volatile (".machine push; .machine \"power6\"; " \
Packit 6c4009
		  "mtfsfi 7,0,1; .machine pop"); \
Packit 363171
	   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 6c4009
  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 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit edaf47
/* Same as __fesetround_inline, however without runtime check to use DFP
Packit edaf47
   mtfsfi syntax (as relax_fenv_state) or if round value is valid.  */
Packit edaf47
static inline void
Packit edaf47
__fesetround_inline_nocheck (const int round)
Packit edaf47
{
Packit edaf47
  asm volatile ("mtfsfi 7,%0" : : "i" (round));
Packit edaf47
}
Packit edaf47
Packit b1849c
#define FPSCR_MASK(bit) (1 << (31 - (bit)))
Packit b1849c
Packit 6c4009
/* Definitions of all the FPSCR bit numbers */
Packit 6c4009
enum {
Packit 6c4009
  FPSCR_FX = 0,    /* exception summary */
Packit b1849c
#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
Packit 6c4009
  FPSCR_FEX,       /* enabled exception summary */
Packit b1849c
#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
Packit 6c4009
  FPSCR_VX,        /* invalid operation summary */
Packit b1849c
#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
Packit 6c4009
  FPSCR_OX,        /* overflow */
Packit b1849c
#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
Packit 6c4009
  FPSCR_UX,        /* underflow */
Packit b1849c
#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
Packit 6c4009
  FPSCR_ZX,        /* zero divide */
Packit b1849c
#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
Packit 6c4009
  FPSCR_XX,        /* inexact */
Packit b1849c
#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
Packit 6c4009
  FPSCR_VXSNAN,    /* invalid operation for sNaN */
Packit b1849c
#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
Packit 6c4009
  FPSCR_VXISI,     /* invalid operation for Inf-Inf */
Packit b1849c
#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
Packit 6c4009
  FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
Packit b1849c
#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
Packit 6c4009
  FPSCR_VXZDZ,     /* invalid operation for 0/0 */
Packit b1849c
#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
Packit 6c4009
  FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
Packit b1849c
#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
Packit 6c4009
  FPSCR_VXVC,      /* invalid operation for invalid compare */
Packit b1849c
#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
Packit 6c4009
  FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
Packit b1849c
#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
Packit 6c4009
  FPSCR_FI,        /* fraction inexact */
Packit b1849c
#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
Packit 6c4009
  FPSCR_FPRF_C,    /* result class descriptor */
Packit b1849c
#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
Packit 6c4009
  FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
Packit b1849c
#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
Packit 6c4009
  FPSCR_FPRF_FG,   /* result greater than */
Packit b1849c
#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
Packit 6c4009
  FPSCR_FPRF_FE,   /* result equal to */
Packit b1849c
#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
Packit 6c4009
  FPSCR_FPRF_FU,   /* result unordered */
Packit b1849c
#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 b1849c
#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
Packit 6c4009
  FPSCR_VXSQRT,    /* invalid operation for square root */
Packit b1849c
#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
Packit 6c4009
  FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
Packit b1849c
#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
Packit 6c4009
  FPSCR_VE,        /* invalid operation exception enable */
Packit b1849c
#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
Packit 6c4009
  FPSCR_OE,        /* overflow exception enable */
Packit b1849c
#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
Packit 6c4009
  FPSCR_UE,        /* underflow exception enable */
Packit b1849c
#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
Packit 6c4009
  FPSCR_ZE,        /* zero divide exception enable */
Packit b1849c
#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
Packit 6c4009
  FPSCR_XE,        /* inexact exception enable */
Packit b1849c
#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
Packit 6c4009
#ifdef _ARCH_PWR6
Packit 6c4009
  FPSCR_29,        /* Reserved in ISA 2.05  */
Packit b1849c
#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
Packit 6c4009
#else
Packit b1849c
  FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
Packit b1849c
#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 b1849c
  FPSCR_RN_hi,
Packit b1849c
#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
Packit b1849c
  FPSCR_RN_lo
Packit b1849c
#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
Packit 6c4009
};
Packit 6c4009
Packit b1849c
#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
Packit b1849c
#define FPSCR_ENABLES_MASK \
Packit b1849c
  (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
Packit b1849c
#define FPSCR_BASIC_EXCEPTIONS_MASK \
Packit b1849c
  (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
Packit b1849c
Packit b1849c
#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
Packit b1849c
Packit b1849c
/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
Packit b1849c
   in the FPSCR, albeit shifted to different but corresponding locations.
Packit b1849c
   Similarly, the exception indicator bits in the FPSCR correspond one-to-one
Packit b1849c
   with the exception enable bits. It is thus possible to map the FENV(1)
Packit b1849c
   exceptions directly to the FPSCR enables with a simple mask and shift,
Packit b1849c
   and vice versa. */
Packit b1849c
#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
Packit b1849c
Packit 6c4009
static inline int
Packit 6c4009
fenv_reg_to_exceptions (unsigned long long l)
Packit 6c4009
{
Packit b1849c
  return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
Packit b1849c
}
Packit b1849c
Packit b1849c
static inline unsigned long long
Packit b1849c
fenv_exceptions_to_reg (int excepts)
Packit b1849c
{
Packit b1849c
  return (unsigned long long)
Packit b1849c
    (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 */