From 5b5b04d6282df0364424c6f2c0462e5c1a4394b0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Sat, 3 Nov 2012 19:48:53 +0000 Subject: Make fma use of Dekker and Knuth algorithms use round-to-nearest (bug 14796). --- ChangeLog | 41 +++++++++++++++++++++ NEWS | 2 +- include/fenv.h | 1 + math/fclrexcpt.c | 1 + math/libm-test.inc | 64 +++++++++++++++++++++++++++++++++ ports/ChangeLog.alpha | 3 ++ ports/ChangeLog.am33 | 3 ++ ports/ChangeLog.arm | 2 ++ ports/ChangeLog.hppa | 3 ++ ports/ChangeLog.ia64 | 3 ++ ports/ChangeLog.m68k | 3 ++ ports/ChangeLog.mips | 3 ++ ports/ChangeLog.powerpc | 5 +++ ports/sysdeps/alpha/fpu/fclrexcpt.c | 3 +- ports/sysdeps/am33/fpu/fclrexcpt.c | 3 +- ports/sysdeps/arm/fclrexcpt.c | 1 + ports/sysdeps/hppa/fpu/fclrexcpt.c | 3 +- ports/sysdeps/ia64/fpu/fclrexcpt.c | 3 +- ports/sysdeps/m68k/fpu/fclrexcpt.c | 3 +- ports/sysdeps/mips/fpu/fclrexcpt.c | 3 +- ports/sysdeps/powerpc/nofpu/fclrexcpt.c | 3 +- sysdeps/generic/math_private.h | 16 +++++++++ sysdeps/i386/fpu/fclrexcpt.c | 3 +- sysdeps/i386/fpu/fenv_private.h | 23 ++++++++++++ sysdeps/ieee754/dbl-64/s_fma.c | 18 ++++++++-- sysdeps/ieee754/ldbl-128/s_fmal.c | 18 ++++++++-- sysdeps/ieee754/ldbl-96/s_fma.c | 18 ++++++++-- sysdeps/ieee754/ldbl-96/s_fmal.c | 18 ++++++++-- sysdeps/powerpc/fpu/fclrexcpt.c | 3 +- sysdeps/s390/fpu/fclrexcpt.c | 3 +- sysdeps/sh/sh4/fpu/fclrexcpt.c | 1 + sysdeps/sparc/fpu/fclrexcpt.c | 3 +- sysdeps/sparc/fpu/fenv_private.h | 12 +++++++ sysdeps/x86_64/fpu/fclrexcpt.c | 3 +- 34 files changed, 274 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index d40c31c3eb..7b0c9d4364 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,46 @@ 2012-11-03 Joseph Myers + [BZ #14796] + * sysdeps/ieee754/dbl-64/s_fma.c (__fma): Set rounding mode to + FE_TONEAREST before applying Dekker multiplication and Knuth + addition. Clear inexact exceptions and check for exact zero + results afterwards. + * sysdeps/ieee754/ldbl-128/s_fmal.c (__fmal): Likewise. + * sysdeps/ieee754/ldbl-96/s_fma.c (__fma): Likewise. + * sysdeps/ieee754/ldbl-96/s_fmal.c (__fmal): Likewise. + * math/libm-test.inc (fma_test): Add more tests. + (fma_test_towardzero): Likewise. + (fma_test_downward): Likewise. + (fma_test_upward): Likewise. + * sysdeps/generic/math_private.h (default_libc_fesetround): New + function. + (libc_fesetround): New macro. + (libc_fesetroundf): Likewise. + (libc_fesetroundl): Likewise. + * sysdeps/i386/fpu/fenv_private.h (libc_fesetround_sse): New + function. + (libc_fesetround_387): Likewise. + (libc_fesetroundf): New macro. + (libc_fesetround): Likewise. + (libc_fesetroundl): Likewise. + * sysdeps/sparc/fpu/fenv_private.h (libc_fesetround): New + function. + (libc_fesetroundf): New macro. + (libc_fesetround): Likewise. + (libc_fesetroundl): Likewise. + * include/fenv.h (feclearexcept): Add libm_hidden_proto. + * math/fclrexcpt.c (feclearexcept): Add libm_hidden_ver. + * sysdeps/i386/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + * sysdeps/powerpc/fpu/fclrexcpt.c (feclearexcept): Likewise. + * sysdeps/s390/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_def. + * sysdeps/sh/sh4/fpu/fclrexcpt.c (feclearexcept): Likewise. + * sysdeps/sparc/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + * sysdeps/x86_64/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_def. + [BZ #3439] * sysdeps/powerpc/bits/fenv.h (FE_INEXACT): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/NEWS b/NEWS index fba6689023..25af21ce1a 100644 --- a/NEWS +++ b/NEWS @@ -18,7 +18,7 @@ Version 2.17 14532, 14538, 14543, 14544, 14545, 14557, 14562, 14568, 14576, 14579, 14583, 14587, 14595, 14602, 14610, 14621, 14638, 14645, 14648, 14652, 14660, 14661, 14669, 14683, 14694, 14716, 14743, 14767, 14783, 14784, - 14785. + 14785, 14796. * Support for STT_GNU_IFUNC symbols added for s390 and s390x. Optimized versions of memcpy, memset, and memcmp added for System z10 and diff --git a/include/fenv.h b/include/fenv.h index 67ef385bbf..ed6d1394ba 100644 --- a/include/fenv.h +++ b/include/fenv.h @@ -20,6 +20,7 @@ libm_hidden_proto (fesetround) libm_hidden_proto (feholdexcept) libm_hidden_proto (feupdateenv) libm_hidden_proto (fetestexcept) +libm_hidden_proto (feclearexcept) #endif #endif diff --git a/math/fclrexcpt.c b/math/fclrexcpt.c index dcdcfbbe99..bbf1011a65 100644 --- a/math/fclrexcpt.c +++ b/math/fclrexcpt.c @@ -30,6 +30,7 @@ __feclearexcept (int excepts) strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); stub_warning (feclearexcept) diff --git a/math/libm-test.inc b/math/libm-test.inc index 258c960ec1..48241e02f8 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -4649,6 +4649,10 @@ fma_test (void) TEST_fff_f (fma, 0x1p-149, -0x1p-149, 0x1p-149, 0x1p-149, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, 0x1p-149, -0x1p-149, -0x1p-149, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, -0x1p-149, -0x1p-149, -0x1p-149, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffp0, 0x0.fffp0, -0x0.ffep0, 0x1p-24); + TEST_fff_f (fma, 0x0.fffp0, -0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, 0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, -0x0.fffp0, -0x0.ffep0, 0x1p-24); #endif #if defined (TEST_DOUBLE) && DBL_MANT_DIG == 53 TEST_fff_f (fma, 0x1.7fp+13, 0x1.0000000000001p+0, 0x1.ffep-48, 0x1.7f00000000001p+13); @@ -4695,6 +4699,10 @@ fma_test (void) TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, 0x1p-1074, 0x1p-1074, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, 0x1p-1074, -0x1p-1074, -0x1p-1074, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, -0x1p-1074, -0x1p-1074, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 64 TEST_fff_f (fma, -0x8.03fcp+3696L, 0xf.fffffffffffffffp-6140L, 0x8.3ffffffffffffffp-2450L, -0x8.01ecp-2440L); @@ -4727,6 +4735,10 @@ fma_test (void) TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, 0x1p-16445L, 0x1p-16445L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, -0x1p-16445L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 113 TEST_fff_f (fma, 0x1.bb2de33e02ccbbfa6e245a7c1f71p-2584L, -0x1.6b500daf0580d987f1bc0cadfcddp-13777L, 0x1.613cd91d9fed34b33820e5ab9d8dp-16378L, -0x1.3a79fb50eb9ce887cffa0f09bd9fp-16360L); @@ -4766,6 +4778,10 @@ fma_test (void) TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, 0x1p-16494L, 0x1p-16494L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, -0x1p-16494L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); #endif END (fma); @@ -4846,6 +4862,10 @@ fma_test_towardzero (void) TEST_fff_f (fma, 0x1p-149, -0x1p-149, 0x1p-149, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, 0x1p-149, -0x1p-149, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, -0x1p-149, -0x1p-149, -0x1p-149, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffp0, 0x0.fffp0, -0x0.ffep0, 0x1p-24); + TEST_fff_f (fma, 0x0.fffp0, -0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, 0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, -0x0.fffp0, -0x0.ffep0, 0x1p-24); #endif #if defined (TEST_DOUBLE) && DBL_MANT_DIG == 53 TEST_fff_f (fma, 0x1.4p-1022, 0x1.0000000000002p-1, 0x1p-1024, 0x1.c000000000002p-1023, UNDERFLOW_EXCEPTION); @@ -4872,6 +4892,10 @@ fma_test_towardzero (void) TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, 0x1p-1074, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, 0x1p-1074, -0x1p-1074, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, -0x1p-1074, -0x1p-1074, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 64 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000004p-1L, 0x1p-16384L, 0x1.c000000000000004p-16383L, UNDERFLOW_EXCEPTION); @@ -4898,6 +4922,10 @@ fma_test_towardzero (void) TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, 0x1p-16445L, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, 0x1p-16445L, -0x1p-16445L, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, -0x1p-16445L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 113 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000000000000000002p-1L, 0x1p-16384L, 0x1.c000000000000000000000000002p-16383L, UNDERFLOW_EXCEPTION); @@ -4924,6 +4952,10 @@ fma_test_towardzero (void) TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, 0x1p-16494L, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, 0x1p-16494L, -0x1p-16494L, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, -0x1p-16494L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); #endif } @@ -5007,6 +5039,10 @@ fma_test_downward (void) TEST_fff_f (fma, 0x1p-149, -0x1p-149, 0x1p-149, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, 0x1p-149, -0x1p-149, -0x1p-149, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, -0x1p-149, -0x1p-149, -0x1p-148, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffp0, 0x0.fffp0, -0x0.ffep0, 0x1p-24); + TEST_fff_f (fma, 0x0.fffp0, -0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, 0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, -0x0.fffp0, -0x0.ffep0, 0x1p-24); #endif #if defined (TEST_DOUBLE) && DBL_MANT_DIG == 53 TEST_fff_f (fma, 0x1.4p-1022, 0x1.0000000000002p-1, 0x1p-1024, 0x1.c000000000002p-1023, UNDERFLOW_EXCEPTION); @@ -5033,6 +5069,10 @@ fma_test_downward (void) TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, 0x1p-1074, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, 0x1p-1074, -0x1p-1074, -0x1p-1074, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, -0x1p-1074, -0x1p-1073, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 64 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000004p-1L, 0x1p-16384L, 0x1.c000000000000004p-16383L, UNDERFLOW_EXCEPTION); @@ -5059,6 +5099,10 @@ fma_test_downward (void) TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, 0x1p-16445L, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, -0x1p-16444L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 113 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000000000000000002p-1L, 0x1p-16384L, 0x1.c000000000000000000000000002p-16383L, UNDERFLOW_EXCEPTION); @@ -5085,6 +5129,10 @@ fma_test_downward (void) TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, 0x1p-16494L, plus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, -0x1p-16493L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); #endif } @@ -5168,6 +5216,10 @@ fma_test_upward (void) TEST_fff_f (fma, 0x1p-149, -0x1p-149, 0x1p-149, 0x1p-149, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, 0x1p-149, -0x1p-149, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-149, -0x1p-149, -0x1p-149, -0x1p-149, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffp0, 0x0.fffp0, -0x0.ffep0, 0x1p-24); + TEST_fff_f (fma, 0x0.fffp0, -0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, 0x0.fffp0, 0x0.ffep0, -0x1p-24); + TEST_fff_f (fma, -0x0.fffp0, -0x0.fffp0, -0x0.ffep0, 0x1p-24); #endif #if defined (TEST_DOUBLE) && DBL_MANT_DIG == 53 TEST_fff_f (fma, 0x1.4p-1022, 0x1.0000000000002p-1, 0x1p-1024, 0x1.c000000000004p-1023, UNDERFLOW_EXCEPTION); @@ -5194,6 +5246,10 @@ fma_test_upward (void) TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, 0x1p-1074, 0x1p-1074, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, 0x1p-1074, -0x1p-1074, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-1074, -0x1p-1074, -0x1p-1074, -0x1p-1074, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); + TEST_fff_f (fma, 0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, 0x0.fffffffffffff8p0, 0x0.fffffffffffffp0, -0x1p-106); + TEST_fff_f (fma, -0x0.fffffffffffff8p0, -0x0.fffffffffffff8p0, -0x0.fffffffffffffp0, 0x1p-106); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 64 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000004p-1L, 0x1p-16384L, 0x1.c000000000000008p-16383L, UNDERFLOW_EXCEPTION); @@ -5220,6 +5276,10 @@ fma_test_upward (void) TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, 0x1p-16445L, 0x1p-16445L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, 0x1p-16445L, -0x1p-16445L, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16445L, -0x1p-16445L, -0x1p-16445L, -0x1p-16445L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); + TEST_fff_f (fma, 0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, 0x0.ffffffffffffffffp0L, 0x0.fffffffffffffffep0L, -0x1p-128L); + TEST_fff_f (fma, -0x0.ffffffffffffffffp0L, -0x0.ffffffffffffffffp0L, -0x0.fffffffffffffffep0L, 0x1p-128L); #endif #if defined (TEST_LDOUBLE) && LDBL_MANT_DIG == 113 TEST_fff_f (fma, 0x1.4p-16382L, 0x1.0000000000000000000000000002p-1L, 0x1p-16384L, 0x1.c000000000000000000000000004p-16383L, UNDERFLOW_EXCEPTION); @@ -5246,6 +5306,10 @@ fma_test_upward (void) TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, 0x1p-16494L, 0x1p-16494L, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, 0x1p-16494L, -0x1p-16494L, minus_zero, UNDERFLOW_EXCEPTION); TEST_fff_f (fma, 0x1p-16494L, -0x1p-16494L, -0x1p-16494L, -0x1p-16494L, UNDERFLOW_EXCEPTION); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); + TEST_fff_f (fma, 0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffff8p0L, 0x0.ffffffffffffffffffffffffffffp0L, -0x1p-226L); + TEST_fff_f (fma, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffff8p0L, -0x0.ffffffffffffffffffffffffffffp0L, 0x1p-226L); #endif } diff --git a/ports/ChangeLog.alpha b/ports/ChangeLog.alpha index de1837ed7d..ca446c8a89 100644 --- a/ports/ChangeLog.alpha +++ b/ports/ChangeLog.alpha @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/alpha/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + [BZ #3439] * sysdeps/alpha/fpu/bits/fenv.h (FE_DENORMAL): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.am33 b/ports/ChangeLog.am33 index c018fbaabf..4e6d40b4c5 100644 --- a/ports/ChangeLog.am33 +++ b/ports/ChangeLog.am33 @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/am33/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + [BZ #3439] * sysdeps/am33/fpu/bits/fenv.h (FE_INEXACT): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm index 54c5cf0392..234883e17a 100644 --- a/ports/ChangeLog.arm +++ b/ports/ChangeLog.arm @@ -1,5 +1,7 @@ 2012-11-03 Joseph Myers + * sysdeps/arm/fclrexcpt.c (feclearexcept): Add libm_hidden_ver. + [BZ #3439] * sysdeps/arm/bits/fenv.h (FE_INVALID): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.hppa b/ports/ChangeLog.hppa index a5da64a096..3e8d522a07 100644 --- a/ports/ChangeLog.hppa +++ b/ports/ChangeLog.hppa @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/hppa/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_def. + [BZ #3439] * sysdeps/hppa/fpu/bits/fenv.h (FE_INVALID): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.ia64 b/ports/ChangeLog.ia64 index 0d629c613e..0b3361af08 100644 --- a/ports/ChangeLog.ia64 +++ b/ports/ChangeLog.ia64 @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/ia64/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_def. + [BZ #3439] * sysdeps/ia64/bits/fenv.h (FE_INEXACT): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.m68k b/ports/ChangeLog.m68k index 2bc29908a9..206702e1fe 100644 --- a/ports/ChangeLog.m68k +++ b/ports/ChangeLog.m68k @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/m68k/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + [BZ #3439] * sysdeps/m68k/fpu/bits/fenv.h (FE_INEXACT): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.mips b/ports/ChangeLog.mips index f0f796a734..548d95e1d4 100644 --- a/ports/ChangeLog.mips +++ b/ports/ChangeLog.mips @@ -1,5 +1,8 @@ 2012-11-03 Joseph Myers + * sysdeps/mips/fpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_def. + [BZ #3439] * sysdeps/mips/bits/fenv.h (FE_INEXACT): Define macro to integer constant usable in #if and use that to give value to enum diff --git a/ports/ChangeLog.powerpc b/ports/ChangeLog.powerpc index 758853ed8e..a6fd7821fc 100644 --- a/ports/ChangeLog.powerpc +++ b/ports/ChangeLog.powerpc @@ -1,3 +1,8 @@ +2012-11-03 Joseph Myers + + * sysdeps/powerpc/nofpu/fclrexcpt.c (feclearexcept): Add + libm_hidden_ver. + 2012-10-31 Andreas Schwab * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist: diff --git a/ports/sysdeps/alpha/fpu/fclrexcpt.c b/ports/sysdeps/alpha/fpu/fclrexcpt.c index 2d2bd94db7..84596529c2 100644 --- a/ports/sysdeps/alpha/fpu/fclrexcpt.c +++ b/ports/sysdeps/alpha/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997,99,2000,01 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson , 1997. @@ -43,4 +43,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/ports/sysdeps/am33/fpu/fclrexcpt.c b/ports/sysdeps/am33/fpu/fclrexcpt.c index 2b15f45a63..492ea38ba3 100644 --- a/ports/sysdeps/am33/fpu/fclrexcpt.c +++ b/ports/sysdeps/am33/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Alexandre Oliva based on corresponding file in the MIPS port. @@ -48,4 +48,5 @@ __feclearexcept (int excepts) return 0; } +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/ports/sysdeps/arm/fclrexcpt.c b/ports/sysdeps/arm/fclrexcpt.c index 23435fba78..fb106a5cc6 100644 --- a/ports/sysdeps/arm/fclrexcpt.c +++ b/ports/sysdeps/arm/fclrexcpt.c @@ -54,4 +54,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/ports/sysdeps/hppa/fpu/fclrexcpt.c b/ports/sysdeps/hppa/fpu/fclrexcpt.c index 5d1e593105..bbc2c70803 100644 --- a/ports/sysdeps/hppa/fpu/fclrexcpt.c +++ b/ports/sysdeps/hppa/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by David Huggins-Daines , 2000 @@ -33,3 +33,4 @@ feclearexcept (int excepts) /* Success. */ return 0; } +libm_hidden_def (feclearexcept) diff --git a/ports/sysdeps/ia64/fpu/fclrexcpt.c b/ports/sysdeps/ia64/fpu/fclrexcpt.c index 84f83277b9..c099fd35ab 100644 --- a/ports/sysdeps/ia64/fpu/fclrexcpt.c +++ b/ports/sysdeps/ia64/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Christian Boissat , 1999 and Jes Sorensen , 2000 @@ -36,3 +36,4 @@ feclearexcept (int excepts) /* success */ return 0; } +libm_hidden_def (feclearexcept) diff --git a/ports/sysdeps/m68k/fpu/fclrexcpt.c b/ports/sysdeps/m68k/fpu/fclrexcpt.c index ceda99cb98..cfc8d9e258 100644 --- a/ports/sysdeps/m68k/fpu/fclrexcpt.c +++ b/ports/sysdeps/m68k/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997,99,2000,01 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Schwab @@ -46,4 +46,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/ports/sysdeps/mips/fpu/fclrexcpt.c b/ports/sysdeps/mips/fpu/fclrexcpt.c index f97d892605..f4709b4d28 100644 --- a/ports/sysdeps/mips/fpu/fclrexcpt.c +++ b/ports/sysdeps/mips/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + Copyright (C) 1998-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Jaeger , 1998. @@ -44,3 +44,4 @@ feclearexcept (int excepts) /* Success. */ return 0; } +libm_hidden_def (feclearexcept) diff --git a/ports/sysdeps/powerpc/nofpu/fclrexcpt.c b/ports/sysdeps/powerpc/nofpu/fclrexcpt.c index 768fd8ff84..f4b9016ea0 100644 --- a/ports/sysdeps/powerpc/nofpu/fclrexcpt.c +++ b/ports/sysdeps/powerpc/nofpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear floating-point exceptions (soft-float edition). - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002-2012 Free Software Foundation, Inc. Contributed by Aldy Hernandez , 2002. This file is part of the GNU C Library. @@ -33,4 +33,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/sysdeps/generic/math_private.h b/sysdeps/generic/math_private.h index b375bc0c56..7661788e6d 100644 --- a/sysdeps/generic/math_private.h +++ b/sysdeps/generic/math_private.h @@ -401,6 +401,22 @@ default_libc_feholdexcept (fenv_t *e) # define libc_feholdexceptl default_libc_feholdexcept #endif +static __always_inline void +default_libc_fesetround (int r) +{ + (void) fesetround (r); +} + +#ifndef libc_fesetround +# define libc_fesetround default_libc_fesetround +#endif +#ifndef libc_fesetroundf +# define libc_fesetroundf default_libc_fesetround +#endif +#ifndef libc_fesetroundl +# define libc_fesetroundl default_libc_fesetround +#endif + static __always_inline void default_libc_feholdexcept_setround (fenv_t *e, int r) { diff --git a/sysdeps/i386/fpu/fclrexcpt.c b/sysdeps/i386/fpu/fclrexcpt.c index f24d07f3d1..f28ef6b3fa 100644 --- a/sysdeps/i386/fpu/fclrexcpt.c +++ b/sysdeps/i386/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997,99,2000, 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. @@ -65,4 +65,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/sysdeps/i386/fpu/fenv_private.h b/sysdeps/i386/fpu/fenv_private.h index f33f57c39c..03f4c97a9c 100644 --- a/sysdeps/i386/fpu/fenv_private.h +++ b/sysdeps/i386/fpu/fenv_private.h @@ -76,6 +76,24 @@ libc_feholdexcept_387 (fenv_t *e) "st(4)", "st(5)", "st(6)", "st(7)"); } +static __always_inline void +libc_fesetround_sse (int r) +{ + unsigned int mxcsr; + asm (STMXCSR " %0" : "=m" (*&mxcsr)); + mxcsr = (mxcsr & ~0x6000) | (r << 3); + asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr)); +} + +static __always_inline void +libc_fesetround_387 (int r) +{ + fpu_control_t cw; + _FPU_GETCW (cw); + cw = (cw & ~0xc00) | r; + _FPU_SETCW (cw); +} + static __always_inline void libc_feholdexcept_setround_sse (fenv_t *e, int r) { @@ -247,6 +265,7 @@ libc_feresetround_387 (fenv_t *e) #ifdef __SSE_MATH__ # define libc_feholdexceptf libc_feholdexcept_sse +# define libc_fesetroundf libc_fesetround_sse # define libc_feholdexcept_setroundf libc_feholdexcept_setround_sse # define libc_fetestexceptf libc_fetestexcept_sse # define libc_fesetenvf libc_fesetenv_sse @@ -256,6 +275,7 @@ libc_feresetround_387 (fenv_t *e) # define libc_feresetroundf libc_feresetround_sse #else # define libc_feholdexceptf libc_feholdexcept_387 +# define libc_fesetroundf libc_fesetround_387 # define libc_feholdexcept_setroundf libc_feholdexcept_setround_387 # define libc_fetestexceptf libc_fetestexcept_387 # define libc_fesetenvf libc_fesetenv_387 @@ -267,6 +287,7 @@ libc_feresetround_387 (fenv_t *e) #ifdef __SSE2_MATH__ # define libc_feholdexcept libc_feholdexcept_sse +# define libc_fesetround libc_fesetround_sse # define libc_feholdexcept_setround libc_feholdexcept_setround_sse # define libc_fetestexcept libc_fetestexcept_sse # define libc_fesetenv libc_fesetenv_sse @@ -276,6 +297,7 @@ libc_feresetround_387 (fenv_t *e) # define libc_feresetround libc_feresetround_sse #else # define libc_feholdexcept libc_feholdexcept_387 +# define libc_fesetround libc_fesetround_387 # define libc_feholdexcept_setround libc_feholdexcept_setround_387 # define libc_fetestexcept libc_fetestexcept_387 # define libc_fesetenv libc_fesetenv_387 @@ -286,6 +308,7 @@ libc_feresetround_387 (fenv_t *e) #endif /* __SSE2_MATH__ */ #define libc_feholdexceptl libc_feholdexcept_387 +#define libc_fesetroundl libc_fesetround_387 #define libc_feholdexcept_setroundl libc_feholdexcept_setround_387 #define libc_fetestexceptl libc_fetestexcept_387 #define libc_fesetenvl libc_fesetenv_387 diff --git a/sysdeps/ieee754/dbl-64/s_fma.c b/sysdeps/ieee754/dbl-64/s_fma.c index 68c63a1987..07fe715617 100644 --- a/sysdeps/ieee754/dbl-64/s_fma.c +++ b/sysdeps/ieee754/dbl-64/s_fma.c @@ -167,6 +167,9 @@ __fma (double x, double y, double z) if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0)) return x * y + z; + fenv_t env; + libc_feholdexcept_setround (&env, FE_TONEAREST); + /* Multiplication m1 + m2 = x * y using Dekker's algorithm. */ #define C ((1 << (DBL_MANT_DIG + 1) / 2) + 1) double x1 = x * C; @@ -185,9 +188,20 @@ __fma (double x, double y, double z) t1 = m1 - t1; t2 = z - t2; double a2 = t1 + t2; + feclearexcept (FE_INEXACT); - fenv_t env; - libc_feholdexcept_setround (&env, FE_TOWARDZERO); + /* If the result is an exact zero, ensure it has the correct + sign. */ + if (a1 == 0 && m2 == 0) + { + libc_feupdateenv (&env); + /* Ensure that round-to-nearest value of z + m1 is not + reused. */ + asm volatile ("" : "=m" (z) : "m" (z)); + return z + m1; + } + + libc_fesetround (FE_TOWARDZERO); /* Perform m2 + a2 addition with round to odd. */ u.d = a2 + m2; diff --git a/sysdeps/ieee754/ldbl-128/s_fmal.c b/sysdeps/ieee754/ldbl-128/s_fmal.c index c6a3d71f1c..d576403b25 100644 --- a/sysdeps/ieee754/ldbl-128/s_fmal.c +++ b/sysdeps/ieee754/ldbl-128/s_fmal.c @@ -170,6 +170,10 @@ __fmal (long double x, long double y, long double z) if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0)) return x * y + z; + fenv_t env; + feholdexcept (&env); + fesetround (FE_TONEAREST); + /* Multiplication m1 + m2 = x * y using Dekker's algorithm. */ #define C ((1LL << (LDBL_MANT_DIG + 1) / 2) + 1) long double x1 = x * C; @@ -188,9 +192,19 @@ __fmal (long double x, long double y, long double z) t1 = m1 - t1; t2 = z - t2; long double a2 = t1 + t2; + feclearexcept (FE_INEXACT); + + /* If the result is an exact zero, ensure it has the correct + sign. */ + if (a1 == 0 && m2 == 0) + { + feupdateenv (&env); + /* Ensure that round-to-nearest value of z + m1 is not + reused. */ + asm volatile ("" : "=m" (z) : "m" (z)); + return z + m1; + } - fenv_t env; - feholdexcept (&env); fesetround (FE_TOWARDZERO); /* Perform m2 + a2 addition with round to odd. */ u.d = a2 + m2; diff --git a/sysdeps/ieee754/ldbl-96/s_fma.c b/sysdeps/ieee754/ldbl-96/s_fma.c index 001d8063d4..bf2d794c9b 100644 --- a/sysdeps/ieee754/ldbl-96/s_fma.c +++ b/sysdeps/ieee754/ldbl-96/s_fma.c @@ -42,6 +42,10 @@ __fma (double x, double y, double z) if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0)) return x * y + z; + fenv_t env; + feholdexcept (&env); + fesetround (FE_TONEAREST); + /* Multiplication m1 + m2 = x * y using Dekker's algorithm. */ #define C ((1ULL << (LDBL_MANT_DIG + 1) / 2) + 1) long double x1 = (long double) x * C; @@ -60,9 +64,19 @@ __fma (double x, double y, double z) t1 = m1 - t1; t2 = z - t2; long double a2 = t1 + t2; + feclearexcept (FE_INEXACT); + + /* If the result is an exact zero, ensure it has the correct + sign. */ + if (a1 == 0 && m2 == 0) + { + feupdateenv (&env); + /* Ensure that round-to-nearest value of z + m1 is not + reused. */ + asm volatile ("" : "=m" (z) : "m" (z)); + return z + m1; + } - fenv_t env; - feholdexcept (&env); fesetround (FE_TOWARDZERO); /* Perform m2 + a2 addition with round to odd. */ a2 = a2 + m2; diff --git a/sysdeps/ieee754/ldbl-96/s_fmal.c b/sysdeps/ieee754/ldbl-96/s_fmal.c index b5fdcba6bc..32e71a18ba 100644 --- a/sysdeps/ieee754/ldbl-96/s_fmal.c +++ b/sysdeps/ieee754/ldbl-96/s_fmal.c @@ -168,6 +168,10 @@ __fmal (long double x, long double y, long double z) if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0)) return x * y + z; + fenv_t env; + feholdexcept (&env); + fesetround (FE_TONEAREST); + /* Multiplication m1 + m2 = x * y using Dekker's algorithm. */ #define C ((1LL << (LDBL_MANT_DIG + 1) / 2) + 1) long double x1 = x * C; @@ -186,9 +190,19 @@ __fmal (long double x, long double y, long double z) t1 = m1 - t1; t2 = z - t2; long double a2 = t1 + t2; + feclearexcept (FE_INEXACT); + + /* If the result is an exact zero, ensure it has the correct + sign. */ + if (a1 == 0 && m2 == 0) + { + feupdateenv (&env); + /* Ensure that round-to-nearest value of z + m1 is not + reused. */ + asm volatile ("" : "=m" (z) : "m" (z)); + return z + m1; + } - fenv_t env; - feholdexcept (&env); fesetround (FE_TOWARDZERO); /* Perform m2 + a2 addition with round to odd. */ u.d = a2 + m2; diff --git a/sysdeps/powerpc/fpu/fclrexcpt.c b/sysdeps/powerpc/fpu/fclrexcpt.c index 87376bfe97..e99cc58ace 100644 --- a/sysdeps/powerpc/fpu/fclrexcpt.c +++ b/sysdeps/powerpc/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997,99,2000,01 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -44,4 +44,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/sysdeps/s390/fpu/fclrexcpt.c b/sysdeps/s390/fpu/fclrexcpt.c index 2352d74b07..3e8d9bb3aa 100644 --- a/sysdeps/s390/fpu/fclrexcpt.c +++ b/sysdeps/s390/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -37,3 +37,4 @@ feclearexcept (int excepts) /* Success. */ return 0; } +libm_hidden_def (feclearexcept) diff --git a/sysdeps/sh/sh4/fpu/fclrexcpt.c b/sysdeps/sh/sh4/fpu/fclrexcpt.c index b4b2ead02c..2d31fa6516 100644 --- a/sysdeps/sh/sh4/fpu/fclrexcpt.c +++ b/sysdeps/sh/sh4/fpu/fclrexcpt.c @@ -39,3 +39,4 @@ feclearexcept (int excepts) return 0; } +libm_hidden_def (feclearexcept) diff --git a/sysdeps/sparc/fpu/fclrexcpt.c b/sysdeps/sparc/fpu/fclrexcpt.c index 82b6ac4e2e..50ec4f4ff3 100644 --- a/sysdeps/sparc/fpu/fclrexcpt.c +++ b/sysdeps/sparc/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -39,4 +39,5 @@ strong_alias (__feclearexcept, __old_feclearexcept) compat_symbol (libm, __old_feclearexcept, feclearexcept, GLIBC_2_1); #endif +libm_hidden_ver (__feclearexcept, feclearexcept) versioned_symbol (libm, __feclearexcept, feclearexcept, GLIBC_2_2); diff --git a/sysdeps/sparc/fpu/fenv_private.h b/sysdeps/sparc/fpu/fenv_private.h index a6e8e95a55..8690879ddc 100644 --- a/sysdeps/sparc/fpu/fenv_private.h +++ b/sysdeps/sparc/fpu/fenv_private.h @@ -13,6 +13,15 @@ libc_feholdexcept (fenv_t *e) __fenv_ldfsr(etmp); } +static __always_inline void +libc_fesetround (int r) +{ + fenv_t etmp; + __fenv_stfsr(etmp); + etmp = (etmp & ~__FE_ROUND_MASK) | (r); + __fenv_ldfsr(etmp); +} + static __always_inline void libc_feholdexcept_setround (fenv_t *e, int r) { @@ -79,6 +88,7 @@ libc_feresetround (fenv_t *e) } #define libc_feholdexceptf libc_feholdexcept +#define libc_fesetroundf libc_fesetround #define libc_feholdexcept_setroundf libc_feholdexcept_setround #define libc_fetestexceptf libc_fetestexcept #define libc_fesetenvf libc_fesetenv @@ -87,6 +97,7 @@ libc_feresetround (fenv_t *e) #define libc_feholdsetroundf libc_feholdsetround #define libc_feresetroundf libc_feresetround #define libc_feholdexcept libc_feholdexcept +#define libc_fesetround libc_fesetround #define libc_feholdexcept_setround libc_feholdexcept_setround #define libc_fetestexcept libc_fetestexcept #define libc_fesetenv libc_fesetenv @@ -95,6 +106,7 @@ libc_feresetround (fenv_t *e) #define libc_feholdsetround libc_feholdsetround #define libc_feresetround libc_feresetround #define libc_feholdexceptl libc_feholdexcept +#define libc_fesetroundl libc_fesetround #define libc_feholdexcept_setroundl libc_feholdexcept_setround #define libc_fetestexceptl libc_fetestexcept #define libc_fesetenvl libc_fesetenv diff --git a/sysdeps/x86_64/fpu/fclrexcpt.c b/sysdeps/x86_64/fpu/fclrexcpt.c index 5ef316212a..2d40313394 100644 --- a/sysdeps/x86_64/fpu/fclrexcpt.c +++ b/sysdeps/x86_64/fpu/fclrexcpt.c @@ -1,5 +1,5 @@ /* Clear given exceptions in current floating-point environment. - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -49,3 +49,4 @@ feclearexcept (int excepts) /* Success. */ return 0; } +libm_hidden_def (feclearexcept) -- cgit v1.2.3