Skip to content

Commit

Permalink
Avoid excess range overflowing results from cosh, sinh, lgamma (bug 1…
Browse files Browse the repository at this point in the history
…8980).

Various i386 libm functions return values with excess range and
precision; Wilco Dijkstra's patches to make isfinite etc. expand
inline cause this pre-existing issue to result in test failures (when
e.g. a result that overflows float but not long double gets counted as
overflowing for some purposes but not others).

This patch addresses those cases arising from functions defined in C,
adding a math_narrow_eval macro that forces values to memory to
eliminate excess precision if FLT_EVAL_METHOD indicates this is
needed, and is a no-op otherwise.  I'll convert existing uses of
volatile and asm for this purpose to use the new macro later, once
i386 has clean test results again (which requires fixes for .S files
as well).

Tested for x86_64 and x86.  Committed.

	[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.
  • Loading branch information
Joseph Myers committed Sep 18, 2015
1 parent fe8c2b3 commit c8235dd
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 6 deletions.
16 changes: 16 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
24 changes: 24 additions & 0 deletions sysdeps/generic/math_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sysdeps/ieee754/dbl-64/e_cosh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion sysdeps/ieee754/dbl-64/e_lgamma_r.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sysdeps/ieee754/dbl-64/e_sinh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion sysdeps/ieee754/flt-32/e_coshf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion sysdeps/ieee754/flt-32/e_lgammaf_r.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sysdeps/ieee754/flt-32/e_sinhf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit c8235dd

Please sign in to comment.