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 Service ff7b62
/* Equivalent to fegetenv_register, but only returns bits for
Packit Service ff7b62
   status, exception enables, and mode.  */
Packit Service ff7b62
Packit Service ff7b62
#define fegetenv_status_ISA300()					\
Packit Service ff7b62
  ({register double __fr;						\
Packit Service ff7b62
    __asm__ __volatile__ (						\
Packit Service ff7b62
      ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
Packit Service ff7b62
      : "=f" (__fr));							\
Packit Service ff7b62
    __fr;								\
Packit Service ff7b62
  })
Packit Service ff7b62
Packit Service ff7b62
#ifdef _ARCH_PWR9
Packit Service ff7b62
# define fegetenv_status() fegetenv_status_ISA300()
Packit Service ff7b62
#else
Packit Service ff7b62
# define fegetenv_status()						\
Packit Service ff7b62
  (__glibc_likely (__builtin_cpu_supports ("arch_3_00"))		\
Packit Service ff7b62
   ? fegetenv_status_ISA300()						\
Packit Service ff7b62
   : fegetenv_register()						\
Packit Service ff7b62
  )
Packit Service ff7b62
#endif
Packit Service ff7b62
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 Service 9ef18a
	     asm volatile (".machine push; .machine \"power6\"; " \
Packit 6c4009
		  "mtfsfi 7,0,1; .machine pop"); \
Packit Service 9ef18a
	   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 562438
  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 425722
Packit Service 562438
  return 0;
Packit Service 285c8d
}
Packit Service 285c8d
Packit Service bc2dc3
/* Same as __fesetround_inline, however without runtime check to use DFP
Packit Service bc2dc3
   mtfsfi syntax (as relax_fenv_state) or if round value is valid.  */
Packit Service bc2dc3
static inline void
Packit Service bc2dc3
__fesetround_inline_nocheck (const int round)
Packit Service bc2dc3
{
Packit Service bc2dc3
  asm volatile ("mtfsfi 7,%0" : : "i" (round));
Packit Service bc2dc3
}
Packit Service bc2dc3
Packit 6c4009
/* Definitions of all the FPSCR bit numbers */
Packit 6c4009
enum {
Packit 6c4009
  FPSCR_FX = 0,    /* exception summary */
Packit 6c4009
  FPSCR_FEX,       /* enabled exception summary */
Packit 6c4009
  FPSCR_VX,        /* invalid operation summary */
Packit 6c4009
  FPSCR_OX,        /* overflow */
Packit 6c4009
  FPSCR_UX,        /* underflow */
Packit 6c4009
  FPSCR_ZX,        /* zero divide */
Packit 6c4009
  FPSCR_XX,        /* inexact */
Packit 6c4009
  FPSCR_VXSNAN,    /* invalid operation for sNaN */
Packit 6c4009
  FPSCR_VXISI,     /* invalid operation for Inf-Inf */
Packit 6c4009
  FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
Packit 6c4009
  FPSCR_VXZDZ,     /* invalid operation for 0/0 */
Packit 6c4009
  FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
Packit 6c4009
  FPSCR_VXVC,      /* invalid operation for invalid compare */
Packit 6c4009
  FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
Packit 6c4009
  FPSCR_FI,        /* fraction inexact */
Packit 6c4009
  FPSCR_FPRF_C,    /* result class descriptor */
Packit 6c4009
  FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
Packit 6c4009
  FPSCR_FPRF_FG,   /* result greater than */
Packit 6c4009
  FPSCR_FPRF_FE,   /* result equal to */
Packit 6c4009
  FPSCR_FPRF_FU,   /* result unordered */
Packit 6c4009
  FPSCR_20,        /* reserved */
Packit 6c4009
  FPSCR_VXSOFT,    /* invalid operation set by software */
Packit 6c4009
  FPSCR_VXSQRT,    /* invalid operation for square root */
Packit 6c4009
  FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
Packit 6c4009
  FPSCR_VE,        /* invalid operation exception enable */
Packit 6c4009
  FPSCR_OE,        /* overflow exception enable */
Packit 6c4009
  FPSCR_UE,        /* underflow exception enable */
Packit 6c4009
  FPSCR_ZE,        /* zero divide exception enable */
Packit 6c4009
  FPSCR_XE,        /* inexact exception enable */
Packit 6c4009
#ifdef _ARCH_PWR6
Packit 6c4009
  FPSCR_29,        /* Reserved in ISA 2.05  */
Packit 6c4009
#else
Packit Service 562438
  FPSCR_NI         /* non-IEEE mode (typically, no denormalised numbers) */
Packit 6c4009
#endif /* _ARCH_PWR6 */
Packit 6c4009
  /* the remaining two least-significant bits keep the rounding mode */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
fenv_reg_to_exceptions (unsigned long long l)
Packit 6c4009
{
Packit Service 562438
  int result = 0;
Packit Service 562438
  if (l & (1 << (31 - FPSCR_XE)))
Packit Service 562438
    result |= FE_INEXACT;
Packit Service 562438
  if (l & (1 << (31 - FPSCR_ZE)))
Packit Service 562438
    result |= FE_DIVBYZERO;
Packit Service 562438
  if (l & (1 << (31 - FPSCR_UE)))
Packit Service 562438
    result |= FE_UNDERFLOW;
Packit Service 562438
  if (l & (1 << (31 - FPSCR_OE)))
Packit Service 562438
    result |= FE_OVERFLOW;
Packit Service 562438
  if (l & (1 << (31 - FPSCR_VE)))
Packit Service 562438
    result |= FE_INVALID;
Packit Service 562438
  return result;
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 */