mirror of
https://sourceware.org/git/glibc.git
synced 2025-10-24 13:33:08 +03:00
IEEE 754-2008 defines two ways in which tiny results can be detected, "before rounding" (based on the infinite-precision result) and "after rounding" (based on the result when rounded to normal precision as if the exponent range were unbounded). All binary operations on an architecture must use the same choice of how tininess is detected. soft-fp has so far implemented only before-rounding tininess detection. This patch adds support for after-rounding tininess detection. A new macro _FP_TININESS_AFTER_ROUNDING is added that sfp-machine.h must define (soft-fp is meant to be self-contained so the existing tininess.h files aren't used here, though the information going in sfp-machine.h has been taken from them). The soft-fp macros dealing with raising underflow exceptions then handle the cases where the choice matters specially, rounding a copy of the input to the appropriate precision to see if a value that's tiny before rounding isn't tiny after rounding. Tested for mips64 using GCC trunk (which now uses soft-fp on MIPS, so supporting exceptions and rounding modes for long double where not previously supported - this is the immediate motivation for doing this patch now) together with (a) a patch to sysdeps/mips/math-tests.h to enable exceptions / rounding modes tests for long double for GCC 4.9 and later, and (b) corresponding changes applied to libgcc's soft-fp and sfp-machine.h files. In the libgcc context this is also tested on x86_64 (also an after-rounding architecture) with testcases for __float128 that I intend to add to the GCC testsuite when updating soft-fp there. (To be clear: this patch does not fix any glibc bugs that were user-visible in past releases, since after-rounding architectures didn't use soft-fp in any affected case with support for floating-point exceptions - so there is no corresponding Bugzilla bug. Rather, it works together with the GCC changes to use soft-fp on MIPS to allow previously absent long double functionality to work properly, and allows soft-fp to be used in glibc on after-rounding architectures in cases where it couldn't previously be used.) * soft-fp/op-common.h (_FP_DECL): Mark exponent as possibly unused. (_FP_PACK_SEMIRAW): Determine tininess based on rounding shifted value if _FP_TININESS_AFTER_ROUNDING and unrounded value is in subnormal range. (_FP_PACK_CANONICAL): Determine tininess based on rounding to normal precision if _FP_TININESS_AFTER_ROUNDING and unrounded value has largest subnormal exponent. * soft-fp/soft-fp.h [FP_NO_EXCEPTIONS] (_FP_TININESS_AFTER_ROUNDING): Undefine and redefine to 0. * sysdeps/aarch64/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): New macro. * sysdeps/alpha/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/arm/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/mips/mips64/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/mips/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/powerpc/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/sh/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/sparc/sparc32/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/sparc/sparc64/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise. * sysdeps/tile/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): Likewise.
148 lines
4.4 KiB
C
148 lines
4.4 KiB
C
/* Machine-dependent software floating-point definitions.
|
|
Sparc64 userland (_Q_* and _Qp_*) version.
|
|
Copyright (C) 1997-2014 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
Contributed by Richard Henderson (rth@cygnus.com),
|
|
Jakub Jelinek (jj@ultra.linux.cz) and
|
|
David S. Miller (davem@redhat.com).
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
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 <fpu_control.h>
|
|
#include <fenv.h>
|
|
#include <stdlib.h>
|
|
|
|
#define _FP_W_TYPE_SIZE 64
|
|
#define _FP_W_TYPE unsigned long
|
|
#define _FP_WS_TYPE signed long
|
|
#define _FP_I_TYPE long
|
|
|
|
/* Helper macros for _FP_MUL_MEAT_2_120_240_double. */
|
|
#define _FP_MUL_MEAT_SET_FE_TZ \
|
|
do { \
|
|
static fpu_control_t _fetz = _FPU_RC_DOWN; \
|
|
_FPU_SETCW(_fetz); \
|
|
} while (0)
|
|
#ifndef _FP_MUL_MEAT_RESET_FE
|
|
#define _FP_MUL_MEAT_RESET_FE _FPU_SETCW(_fcw)
|
|
#endif
|
|
|
|
#define _FP_MUL_MEAT_S(R,X,Y) \
|
|
_FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
|
|
#define _FP_MUL_MEAT_D(R,X,Y) \
|
|
_FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
|
|
#define _FP_MUL_MEAT_Q(R,X,Y) \
|
|
_FP_MUL_MEAT_2_120_240_double(_FP_WFRACBITS_Q,R,X,Y, \
|
|
_FP_MUL_MEAT_SET_FE_TZ, \
|
|
_FP_MUL_MEAT_RESET_FE)
|
|
|
|
#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
|
|
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
|
|
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
|
|
|
|
#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
|
|
#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
|
|
#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
|
|
#define _FP_NANSIGN_S 0
|
|
#define _FP_NANSIGN_D 0
|
|
#define _FP_NANSIGN_Q 0
|
|
|
|
#define _FP_KEEPNANFRACP 1
|
|
#define _FP_QNANNEGATEDP 0
|
|
|
|
/* If one NaN is signaling and the other is not,
|
|
* we choose that one, otherwise we choose Y.
|
|
*/
|
|
#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
|
|
do { \
|
|
if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \
|
|
&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
|
|
{ \
|
|
R##_s = X##_s; \
|
|
_FP_FRAC_COPY_##wc(R,X); \
|
|
} \
|
|
else \
|
|
{ \
|
|
R##_s = Y##_s; \
|
|
_FP_FRAC_COPY_##wc(R,Y); \
|
|
} \
|
|
R##_c = FP_CLS_NAN; \
|
|
} while (0)
|
|
|
|
/* Obtain the current rounding mode. */
|
|
#ifndef FP_ROUNDMODE
|
|
#define FP_ROUNDMODE ((_fcw >> 30) & 0x3)
|
|
#endif
|
|
|
|
/* Exception flags. */
|
|
#define FP_EX_INVALID (1 << 4)
|
|
#define FP_EX_OVERFLOW (1 << 3)
|
|
#define FP_EX_UNDERFLOW (1 << 2)
|
|
#define FP_EX_DIVZERO (1 << 1)
|
|
#define FP_EX_INEXACT (1 << 0)
|
|
|
|
#define _FP_TININESS_AFTER_ROUNDING 0
|
|
|
|
#define _FP_DECL_EX \
|
|
fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30)
|
|
|
|
#define FP_INIT_ROUNDMODE \
|
|
do { \
|
|
_FPU_GETCW(_fcw); \
|
|
} while (0)
|
|
|
|
#define FP_TRAPPING_EXCEPTIONS ((_fcw >> 23) & 0x1f)
|
|
#define FP_INHIBIT_RESULTS ((_fcw >> 23) & _fex)
|
|
|
|
/* Simulate exceptions using double arithmetics. */
|
|
extern void __Qp_handle_exceptions(int exc);
|
|
|
|
#define FP_HANDLE_EXCEPTIONS \
|
|
do { \
|
|
if (!_fex) \
|
|
{ \
|
|
/* This is the common case, so we do it inline. \
|
|
* We need to clear cexc bits if any. \
|
|
*/ \
|
|
__asm__ __volatile__("fzero %%f62\n\t" \
|
|
"faddd %%f62, %%f62, %%f62" \
|
|
: : : "f62"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
__Qp_handle_exceptions (_fex); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define QP_HANDLE_EXCEPTIONS(_a) \
|
|
do { \
|
|
if ((_fcw >> 23) & _fex) \
|
|
{ \
|
|
_a; \
|
|
} \
|
|
else \
|
|
{ \
|
|
_fcw = (_fcw & ~0x1fL) | (_fex << 5) | _fex; \
|
|
_FPU_SETCW(_fcw); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define QP_NO_EXCEPTIONS \
|
|
__asm ("fzero %%f62\n\t" \
|
|
"faddd %%f62, %%f62, %%f62" : : : "f62")
|
|
|
|
#define QP_CLOBBER "memory", "f52", "f54", "f56", "f58", "f60", "f62"
|
|
#define QP_CLOBBER_CC QP_CLOBBER , "cc"
|