about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--sysdeps/generic/math_private.h24
-rw-r--r--sysdeps/ieee754/dbl-64/e_cosh.c2
-rw-r--r--sysdeps/ieee754/dbl-64/e_lgamma_r.c2
-rw-r--r--sysdeps/ieee754/dbl-64/e_sinh.c2
-rw-r--r--sysdeps/ieee754/flt-32/e_coshf.c2
-rw-r--r--sysdeps/ieee754/flt-32/e_lgammaf_r.c2
-rw-r--r--sysdeps/ieee754/flt-32/e_sinhf.c2
8 files changed, 46 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 9a89e9d9e5..57b07b36ee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2015-09-18  Joseph Myers  <joseph@codesourcery.com>
+
+	[BZ #18980]
+	* sysdeps/generic/math_private.h: Include <float.h>.
+	(math_narrow_eval): New macro.
+	[FLT_EVAL_METHOD != 0] (excess_precision): Likewise.
+	* sysdeps/ieee754/dbl-64/e_cosh.c (__ieee754_cosh): Use
+	math_narrow_eval on overflowing return value.
+	* sysdeps/ieee754/dbl-64/e_lgamma_r.c (__ieee754_lgamma_r):
+	Likewise.
+	* sysdeps/ieee754/dbl-64/e_sinh.c (__ieee754_sinh): Likewise.
+	* sysdeps/ieee754/flt-32/e_coshf.c (__ieee754_coshf): Likewise.
+	* sysdeps/ieee754/flt-32/e_lgammaf_r.c (__ieee754_lgammaf_r):
+	Likewise.
+	* sysdeps/ieee754/flt-32/e_sinhf.c (__ieee754_sinhf): Likewise.
+
 2015-09-18  Wilco Dijkstra  <wdijkstr@arm.com>
 
 	* include/math.h: Remove __isinf_ns, __isinf_nsf, __isinf_nsl.
diff --git a/sysdeps/generic/math_private.h b/sysdeps/generic/math_private.h
index 6aea8643da..35591eed15 100644
--- a/sysdeps/generic/math_private.h
+++ b/sysdeps/generic/math_private.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <fenv.h>
+#include <float.h>
 #include <get-rounding-mode.h>
 
 /* The original fdlibm code used statements like:
@@ -405,6 +406,29 @@ extern long double __lgamma_productl (long double t, long double x,
 ({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); })
 #endif
 
+/* math_narrow_eval reduces its floating-point argument to the range
+   and precision of its semantic type.  (The original evaluation may
+   still occur with excess range and precision, so the result may be
+   affected by double rounding.)  */
+#if FLT_EVAL_METHOD == 0
+# define math_narrow_eval(x) (x)
+#else
+# if FLT_EVAL_METHOD == 1
+#  define excess_precision(type) __builtin_types_compatible_p (type, float)
+# else
+#  define excess_precision(type) (__builtin_types_compatible_p (type, float) \
+				  || __builtin_types_compatible_p (type, \
+								   double))
+# endif
+# define math_narrow_eval(x)					\
+  ({								\
+    __typeof (x) math_narrow_eval_tmp = (x);			\
+    if (excess_precision (__typeof (math_narrow_eval_tmp)))	\
+      __asm__ ("" : "+m" (math_narrow_eval_tmp));		\
+    math_narrow_eval_tmp;					\
+   })
+#endif
+
 
 /* The standards only specify one variant of the fenv.h interfaces.
    But at least for some architectures we can be more efficient if we
diff --git a/sysdeps/ieee754/dbl-64/e_cosh.c b/sysdeps/ieee754/dbl-64/e_cosh.c
index af3910dd6e..52a5d5007d 100644
--- a/sysdeps/ieee754/dbl-64/e_cosh.c
+++ b/sysdeps/ieee754/dbl-64/e_cosh.c
@@ -83,6 +83,6 @@ __ieee754_cosh (double x)
     return x * x;
 
   /* |x| > overflowthresold, cosh(x) overflow */
-  return huge * huge;
+  return math_narrow_eval (huge * huge);
 }
 strong_alias (__ieee754_cosh, __cosh_finite)
diff --git a/sysdeps/ieee754/dbl-64/e_lgamma_r.c b/sysdeps/ieee754/dbl-64/e_lgamma_r.c
index ea8a9b42fb..da158cba33 100644
--- a/sysdeps/ieee754/dbl-64/e_lgamma_r.c
+++ b/sysdeps/ieee754/dbl-64/e_lgamma_r.c
@@ -296,7 +296,7 @@ __ieee754_lgamma_r(double x, int *signgamp)
 	    r = (x-half)*(t-one)+w;
 	} else
     /* 2**58 <= x <= inf */
-	    r =  x*(__ieee754_log(x)-one);
+	    r =  math_narrow_eval (x*(__ieee754_log(x)-one));
 	/* NADJ is set for negative arguments but not otherwise,
 	   resulting in warnings that it may be used uninitialized
 	   although in the cases where it is used it has always been
diff --git a/sysdeps/ieee754/dbl-64/e_sinh.c b/sysdeps/ieee754/dbl-64/e_sinh.c
index c99d28311d..291bfad0b3 100644
--- a/sysdeps/ieee754/dbl-64/e_sinh.c
+++ b/sysdeps/ieee754/dbl-64/e_sinh.c
@@ -89,6 +89,6 @@ __ieee754_sinh (double x)
     }
 
   /* |x| > overflowthresold, sinh(x) overflow */
-  return x * shuge;
+  return math_narrow_eval (x * shuge);
 }
 strong_alias (__ieee754_sinh, __sinh_finite)
diff --git a/sysdeps/ieee754/flt-32/e_coshf.c b/sysdeps/ieee754/flt-32/e_coshf.c
index dedda47c09..7b223758e1 100644
--- a/sysdeps/ieee754/flt-32/e_coshf.c
+++ b/sysdeps/ieee754/flt-32/e_coshf.c
@@ -58,6 +58,6 @@ __ieee754_coshf (float x)
 	if(ix>=0x7f800000) return x*x;
 
     /* |x| > overflowthresold, cosh(x) overflow */
-	return huge*huge;
+	return math_narrow_eval (huge*huge);
 }
 strong_alias (__ieee754_coshf, __coshf_finite)
diff --git a/sysdeps/ieee754/flt-32/e_lgammaf_r.c b/sysdeps/ieee754/flt-32/e_lgammaf_r.c
index 424c4e7358..45a62c0dab 100644
--- a/sysdeps/ieee754/flt-32/e_lgammaf_r.c
+++ b/sysdeps/ieee754/flt-32/e_lgammaf_r.c
@@ -232,7 +232,7 @@ __ieee754_lgammaf_r(float x, int *signgamp)
 	    r = (x-half)*(t-one)+w;
 	} else
     /* 2**26 <= x <= inf */
-	    r =  x*(__ieee754_logf(x)-one);
+	    r =  math_narrow_eval (x*(__ieee754_logf(x)-one));
 	/* NADJ is set for negative arguments but not otherwise,
 	   resulting in warnings that it may be used uninitialized
 	   although in the cases where it is used it has always been
diff --git a/sysdeps/ieee754/flt-32/e_sinhf.c b/sysdeps/ieee754/flt-32/e_sinhf.c
index 17c2219c0b..a24fa0c4bc 100644
--- a/sysdeps/ieee754/flt-32/e_sinhf.c
+++ b/sysdeps/ieee754/flt-32/e_sinhf.c
@@ -59,6 +59,6 @@ __ieee754_sinhf(float x)
 	}
 
     /* |x| > overflowthresold, sinh(x) overflow */
-	return x*shuge;
+	return math_narrow_eval (x*shuge);
 }
 strong_alias (__ieee754_sinhf, __sinhf_finite)