diff options
author | Stefan Liebler <stli@de.ibm.com> | 2016-01-18 12:48:06 +0100 |
---|---|---|
committer | Stefan Liebler <stli@de.ibm.com> | 2016-01-18 12:48:06 +0100 |
commit | c4d17461e062e730fca4076dd47a2733b3914c51 (patch) | |
tree | 89346046c4bad9bad11d8e8cbbc17c89856c5b2c /sysdeps/ieee754 | |
parent | 4e58b6485989a9462e88d5f683e2100902afd574 (diff) | |
download | glibc-c4d17461e062e730fca4076dd47a2733b3914c51.zip glibc-c4d17461e062e730fca4076dd47a2733b3914c51.tar.gz glibc-c4d17461e062e730fca4076dd47a2733b3914c51.tar.bz2 |
S/390: Do not raise inexact exception in lrint/lround. [BZ #19486]
I get some math test-failures on s390 for float/double/ldouble for
various lrint/lround functions like:
lrint (0x1p64): Exception "Inexact" set
lrint (-0x1p64): Exception "Inexact" set
lround (0x1p64): Exception "Inexact" set
lround (-0x1p64): Exception "Inexact" set
...
GCC emits "convert to fixed" instructions for casting floating point
values to integer values. These instructions raise invalid and inexact
exceptions if the floating point value exceeds the integer type ranges.
This patch enables the various FIX_DBL_LONG_CONVERT_OVERFLOW macros in
order to avoid a cast from floating point to integer type and raise the
invalid exception with feraiseexcept.
The ldbl-128 rint/round functions are now using the same logic.
ChangeLog:
[BZ #19486]
* sysdeps/s390/fix-fp-int-convert-overflow.h: New File.
* sysdeps/generic/fix-fp-int-convert-overflow.h
(FIX_LDBL_LONG_CONVERT_OVERFLOW,
FIX_LDBL_LLONG_CONVERT_OVERFLOW): New define.
* sysdeps/arm/fix-fp-int-convert-overflow.h: Likewise.
* sysdeps/mips/mips32/fpu/fix-fp-int-convert-overflow.h:
Likewise.
* sysdeps/ieee754/ldbl-128/s_lrintl.c (__lrintl):
Avoid conversions to long int where inexact exceptions
could be raised.
* sysdeps/ieee754/ldbl-128/s_lroundl.c (__lroundl):
Likewise.
* sysdeps/ieee754/ldbl-128/s_llrintl.c (__llrintl):
Avoid conversions to long long int where inexact exceptions
could be raised.
* sysdeps/ieee754/ldbl-128/s_llroundl.c (__llroundl):
Likewise.
Diffstat (limited to 'sysdeps/ieee754')
-rw-r--r-- | sysdeps/ieee754/ldbl-128/s_llrintl.c | 7 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128/s_llroundl.c | 11 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128/s_lrintl.c | 7 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128/s_lroundl.c | 11 |
4 files changed, 32 insertions, 4 deletions
diff --git a/sysdeps/ieee754/ldbl-128/s_llrintl.c b/sysdeps/ieee754/ldbl-128/s_llrintl.c index 445cde5..84fc576 100644 --- a/sysdeps/ieee754/ldbl-128/s_llrintl.c +++ b/sysdeps/ieee754/ldbl-128/s_llrintl.c @@ -24,6 +24,7 @@ #include <math.h> #include <math_private.h> +#include <fix-fp-int-convert-overflow.h> static const long double two112[2] = { @@ -91,6 +92,12 @@ __llrintl (long double x) feraiseexcept (t == LLONG_MIN ? FE_INEXACT : FE_INVALID); return LLONG_MIN; } + else if (FIX_LDBL_LLONG_CONVERT_OVERFLOW && x != (long double) LLONG_MIN) + { + feraiseexcept (FE_INVALID); + return sx == 0 ? LLONG_MAX : LLONG_MIN; + } + #endif return (long long int) x; } diff --git a/sysdeps/ieee754/ldbl-128/s_llroundl.c b/sysdeps/ieee754/ldbl-128/s_llroundl.c index e5dd145..bfc81cc 100644 --- a/sysdeps/ieee754/ldbl-128/s_llroundl.c +++ b/sysdeps/ieee754/ldbl-128/s_llroundl.c @@ -23,7 +23,7 @@ #include <math.h> #include <math_private.h> - +#include <fix-fp-int-convert-overflow.h> long long int __llroundl (long double x) @@ -78,7 +78,14 @@ __llroundl (long double x) FE_INVALID must be raised and the return value is unspecified. */ #ifdef FE_INVALID - if (x <= (long double) LLONG_MIN - 0.5L) + if (FIX_LDBL_LLONG_CONVERT_OVERFLOW + && !(sign == -1 && x > (long double) LLONG_MIN - 0.5L)) + { + feraiseexcept (FE_INVALID); + return sign == 1 ? LLONG_MAX : LLONG_MIN; + } + else if (!FIX_LDBL_LLONG_CONVERT_OVERFLOW + && x <= (long double) LLONG_MIN - 0.5L) { /* If truncation produces LLONG_MIN, the cast will not raise the exception, but may raise "inexact". */ diff --git a/sysdeps/ieee754/ldbl-128/s_lrintl.c b/sysdeps/ieee754/ldbl-128/s_lrintl.c index ff4780a..23f828f 100644 --- a/sysdeps/ieee754/ldbl-128/s_lrintl.c +++ b/sysdeps/ieee754/ldbl-128/s_lrintl.c @@ -24,6 +24,7 @@ #include <math.h> #include <math_private.h> +#include <fix-fp-int-convert-overflow.h> static const long double two112[2] = { @@ -120,6 +121,12 @@ __lrintl (long double x) feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID); return LONG_MIN; } + else if (FIX_LDBL_LONG_CONVERT_OVERFLOW && x != (long double) LONG_MIN) + { + feraiseexcept (FE_INVALID); + return sx == 0 ? LONG_MAX : LONG_MIN; + } + #endif return (long int) x; } diff --git a/sysdeps/ieee754/ldbl-128/s_lroundl.c b/sysdeps/ieee754/ldbl-128/s_lroundl.c index 34d2264..f032625 100644 --- a/sysdeps/ieee754/ldbl-128/s_lroundl.c +++ b/sysdeps/ieee754/ldbl-128/s_lroundl.c @@ -23,7 +23,7 @@ #include <math.h> #include <math_private.h> - +#include <fix-fp-int-convert-overflow.h> long int __lroundl (long double x) @@ -87,7 +87,14 @@ __lroundl (long double x) FE_INVALID must be raised and the return value is unspecified. */ #ifdef FE_INVALID - if (x <= (long double) LONG_MIN - 0.5L) + if (FIX_LDBL_LONG_CONVERT_OVERFLOW + && !(sign == -1 && x > (long double) LONG_MIN - 0.5L)) + { + feraiseexcept (FE_INVALID); + return sign == 1 ? LONG_MAX : LONG_MIN; + } + else if (!FIX_LDBL_LONG_CONVERT_OVERFLOW + && x <= (long double) LONG_MIN - 0.5L) { /* If truncation produces LONG_MIN, the cast will not raise the exception, but may raise "inexact". */ |