summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2012-11-03 19:48:53 +0000
committerJoseph Myers <joseph@codesourcery.com>2012-11-03 19:48:53 +0000
commit5b5b04d6282df0364424c6f2c0462e5c1a4394b0 (patch)
treebef8cb91fffbf78e56f18479234abb47ce3054b2
parentfbeafedeea37e0af1984a6511018d159f5ceed6a (diff)
downloadglibc-5b5b04d6282df0364424c6f2c0462e5c1a4394b0.tar.gz
glibc-5b5b04d6282df0364424c6f2c0462e5c1a4394b0.tar.xz
glibc-5b5b04d6282df0364424c6f2c0462e5c1a4394b0.zip
Make fma use of Dekker and Knuth algorithms use round-to-nearest (bug 14796).
-rw-r--r--ChangeLog41
-rw-r--r--NEWS2
-rw-r--r--include/fenv.h1
-rw-r--r--math/fclrexcpt.c1
-rw-r--r--math/libm-test.inc64
-rw-r--r--ports/ChangeLog.alpha3
-rw-r--r--ports/ChangeLog.am333
-rw-r--r--ports/ChangeLog.arm2
-rw-r--r--ports/ChangeLog.hppa3
-rw-r--r--ports/ChangeLog.ia643
-rw-r--r--ports/ChangeLog.m68k3
-rw-r--r--ports/ChangeLog.mips3
-rw-r--r--ports/ChangeLog.powerpc5
-rw-r--r--ports/sysdeps/alpha/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/am33/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/arm/fclrexcpt.c1
-rw-r--r--ports/sysdeps/hppa/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/ia64/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/m68k/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/mips/fpu/fclrexcpt.c3
-rw-r--r--ports/sysdeps/powerpc/nofpu/fclrexcpt.c3
-rw-r--r--sysdeps/generic/math_private.h16
-rw-r--r--sysdeps/i386/fpu/fclrexcpt.c3
-rw-r--r--sysdeps/i386/fpu/fenv_private.h23
-rw-r--r--sysdeps/ieee754/dbl-64/s_fma.c18
-rw-r--r--sysdeps/ieee754/ldbl-128/s_fmal.c18
-rw-r--r--sysdeps/ieee754/ldbl-96/s_fma.c18
-rw-r--r--sysdeps/ieee754/ldbl-96/s_fmal.c18
-rw-r--r--sysdeps/powerpc/fpu/fclrexcpt.c3
-rw-r--r--sysdeps/s390/fpu/fclrexcpt.c3
-rw-r--r--sysdeps/sh/sh4/fpu/fclrexcpt.c1
-rw-r--r--sysdeps/sparc/fpu/fclrexcpt.c3
-rw-r--r--sysdeps/sparc/fpu/fenv_private.h12
-rw-r--r--sysdeps/x86_64/fpu/fclrexcpt.c3
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  <joseph@codesourcery.com>
 
+	[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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
 
+	* 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  <joseph@codesourcery.com>
+
+	* sysdeps/powerpc/nofpu/fclrexcpt.c (feclearexcept): Add
+	libm_hidden_ver.
+
 2012-10-31  Andreas Schwab  <schwab@linux-m68k.org>
 
 	* 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 <rth@tamu.edu>, 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 <aoliva@redhat.com>
    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 <dhd@debian.org>, 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 <Christian.Boissat@cern.ch>, 1999 and
                   Jes Sorensen <Jes.Sorensen@cern.ch>, 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 <schwab@issan.informatik.uni-dortmund.de>
 
@@ -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 <aj@suse.de>, 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 <aldyh@redhat.com>, 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
@@ -402,6 +402,22 @@ default_libc_feholdexcept (fenv_t *e)
 #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)
 {
   feholdexcept (e);
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 <drepper@cygnus.com>, 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
@@ -77,6 +77,24 @@ libc_feholdexcept_387 (fenv_t *e)
 }
 
 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)
 {
   unsigned int mxcsr;
@@ -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
@@ -14,6 +14,15 @@ libc_feholdexcept (fenv_t *e)
 }
 
 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)
 {
   fenv_t etmp;
@@ -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)