From ce245ec69e750d05637be21b59f5013da98f1602 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Fri, 7 Feb 2014 10:14:24 +0000 Subject: [PATCH] _fixdfdi.c: Throw invalid exception if number cannot be represented. 2014-02-07 Andreas Krebbel * config/s390/32/_fixdfdi.c: Throw invalid exception if number cannot be represented. * config/s390/32/_fixsfdi.c: Likewise. * config/s390/32/_fixtfdi.c: Likewise. * config/s390/32/_fixunsdfdi.c: Likewise. * config/s390/32/_fixunssfdi.c: Likewise. * config/s390/32/_fixunstfdi.c: Likewise. 2014-02-07 Andreas Krebbel * gcc.target/s390/fp2int1.c: New testcase. From-SVN: r207596 --- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.target/s390/fp2int1.c | 95 +++++++++++++++++++++++++ libgcc/ChangeLog | 10 +++ libgcc/config/s390/32/_fixdfdi.c | 42 +++++++---- libgcc/config/s390/32/_fixsfdi.c | 44 +++++++----- libgcc/config/s390/32/_fixtfdi.c | 28 ++++++-- libgcc/config/s390/32/_fixunsdfdi.c | 46 +++++++++--- libgcc/config/s390/32/_fixunssfdi.c | 50 +++++++++---- libgcc/config/s390/32/_fixunstfdi.c | 37 ++++++++-- 9 files changed, 290 insertions(+), 66 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/fp2int1.c diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a75accc259d..1a5a636a687 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2014-02-07 Andreas Krebbel + + * gcc.target/s390/fp2int1.c: New testcase. + 2014-02-07 Richard Biener PR middle-end/60092 diff --git a/gcc/testsuite/gcc.target/s390/fp2int1.c b/gcc/testsuite/gcc.target/s390/fp2int1.c new file mode 100644 index 00000000000..4a90a8b91de --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/fp2int1.c @@ -0,0 +1,95 @@ +/* Test for the 32 bit fp to 64 bit int conversion routines. + + On S/390 32 bit we use our own implementations in order to be IEEE + complaint as we are with our machine instructions. These missed to + throw FE_INVALID exceptions in a bunch of cases. */ + +/* { dg-do run { target s390-*-* } } */ +/* { dg-options "-O3 -mesa" } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#define _GNU_SOURCE +#include +#include +#include + +#define INFINITYf (__builtin_inff()) +#define INFINITY (__builtin_inf()) +#define INFINITYl (__builtin_infl()) +#define NANf (__builtin_nanf ("")) +#define NAN (__builtin_nan ("")) +#define NANl (__builtin_nanl ("")) + +#define TESTEXCEPT_FUNC(FUNC, TYPE_FROM, TYPE_TO) \ + TYPE_TO \ + __attribute__((noinline)) FUNC (TYPE_FROM a) \ + { \ + asm volatile ("" : : "f" (a)); \ + return (TYPE_TO)a; \ + } + +#define TESTEXCEPT(FUNC, EXCEPT, EXPECT, VALUE, TYPE_TO) \ + { \ + TYPE_TO b; \ + feclearexcept (FE_ALL_EXCEPT); \ + b = FUNC (VALUE); \ + if ((fetestexcept (EXCEPT) & (EXCEPT)) != EXPECT) \ + { \ + printf ("FAIL in line: %d\n", __LINE__); \ + abort (); \ + } \ + } + +#define TESTEXCEPT_FUNC_ALLFLOATS(FUNC, TYPE_TO) \ + TESTEXCEPT_FUNC (FUNC##_f, float, TYPE_TO); \ + TESTEXCEPT_FUNC (FUNC##_d, double, TYPE_TO); \ + TESTEXCEPT_FUNC (FUNC##_l, long double, TYPE_TO); \ + +#define TESTEXCEPT_ALLFLOATS(FUNC, EXCEPT, EXPECT, VALUE, TYPE_TO) \ + TESTEXCEPT (FUNC##_f, EXCEPT, EXPECT, VALUE##f, TYPE_TO); \ + TESTEXCEPT (FUNC##_d, EXCEPT, EXPECT, VALUE, TYPE_TO); \ + TESTEXCEPT (FUNC##_l, EXCEPT, EXPECT, VALUE##l, TYPE_TO); \ + +TESTEXCEPT_FUNC_ALLFLOATS (a, unsigned long long); +TESTEXCEPT_FUNC_ALLFLOATS (u, long long); + + +int +main () +{ + /* Prevent getting signals. */ + fedisableexcept (FE_INVALID); + + /* To unsigned long long */ + + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, INFINITY, unsigned long long); + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, -INFINITY, unsigned long long); + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, NAN, unsigned long long); + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, -NAN, unsigned long long); + + /* Negative values >-1.0 must not cause FE_INVALID. */ + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, 0, -0x0.ffffffp0, unsigned long long); + /* -1.0 instead must. */ + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, -0x1.0p+0, unsigned long long); + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, 0, 0x1.0p+63, unsigned long long); + TESTEXCEPT_ALLFLOATS (a, FE_INVALID, FE_INVALID, 0x1.0p+64, unsigned long long); + + /* To signed long long */ + + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, INFINITY, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, -INFINITY, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, NAN, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, -NAN, long long); + + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, 0, -0x1.0p+63, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, -0x1.1p+63, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, 0, 0x0.fffffp+63, long long); + TESTEXCEPT_ALLFLOATS (u, FE_INVALID, FE_INVALID, 0x1.0p+63, long long); + + /* If there are additional bits which would not make it into the + integer value no exception is supposed to occur. */ + TESTEXCEPT (u_l, FE_INVALID, 0, -0x1.000000000000000123p+63l, long long); + TESTEXCEPT (u_l, FE_INVALID, FE_INVALID, -0x1.000000000000000223p+63l, long long); + + return 0; +} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 2389df55738..64be83de082 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,13 @@ +2014-02-07 Andreas Krebbel + + * config/s390/32/_fixdfdi.c: Throw invalid exception if number + cannot be represented. + * config/s390/32/_fixsfdi.c: Likewise. + * config/s390/32/_fixtfdi.c: Likewise. + * config/s390/32/_fixunsdfdi.c: Likewise. + * config/s390/32/_fixunssfdi.c: Likewise. + * config/s390/32/_fixunstfdi.c: Likewise. + 2014-02-07 Richard Sandiford * configure.ac (libgcc_cv_mips_hard_float): New. diff --git a/libgcc/config/s390/32/_fixdfdi.c b/libgcc/config/s390/32/_fixdfdi.c index b1ba06d7335..e6dd4d11441 100644 --- a/libgcc/config/s390/32/_fixdfdi.c +++ b/libgcc/config/s390/32/_fixdfdi.c @@ -27,12 +27,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef __s390x__ #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define EXCESSD 1022 +#define EXPONENT_BIAS 1023 +#define MANTISSA_BITS 52 +#define PRECISION (MANTISSA_BITS + 1) #define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) +#define SIGN(fp) ((fp.l.upper) & SIGNBIT) #define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) #define FRACD_LL(fp) (fp.ll & (HIDDEND_LL-1)) -#define HIDDEND_LL ((UDItype_x)1 << 52) +#define HIDDEND_LL ((UDItype_x)1 << MANTISSA_BITS) +#define LLONG_MAX 9223372036854775807LL +#define LLONG_MIN (-LLONG_MAX - 1LL) typedef int DItype_x __attribute__ ((mode (DI))); typedef unsigned int UDItype_x __attribute__ ((mode (DI))); @@ -48,6 +52,12 @@ union double_long { UDItype_x ll; }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + DItype_x __fixdfdi (double a1); /* convert double to int */ @@ -61,29 +71,33 @@ __fixdfdi (double a1) dl1.d = a1; /* +/- 0, denormalized */ - if (!EXPD (dl1)) return 0; - exp = EXPD (dl1) - EXCESSD - 53; + /* The exponent - considered the binary point at the right end of + the mantissa. */ + exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; /* number < 1 */ - - if (exp < -53) + if (exp <= -PRECISION) return 0; /* NaN */ if ((EXPD(dl1) == 0x7ff) && (FRACD_LL(dl1) != 0)) /* NaN */ - return 0x8000000000000000ULL; + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0x8000000000000000ULL; + } /* Number big number & +/- inf */ - if (exp >= 11) { - l = (long long)1<<63; - if (!SIGND(dl1)) - l--; - return l; + /* Don't throw an exception for -1p+63 */ + if (!SIGN (dl1) || exp > 11 || FRACD_LL (dl1) != 0) + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return SIGN (dl1) ? LLONG_MIN : LLONG_MAX; } l = MANTD_LL(dl1); @@ -94,6 +108,6 @@ __fixdfdi (double a1) else l >>= -exp; - return (SIGND (dl1) ? -l : l); + return (SIGN (dl1) ? -l : l); } #endif /* !__s390x__ */ diff --git a/libgcc/config/s390/32/_fixsfdi.c b/libgcc/config/s390/32/_fixsfdi.c index dbf40b43a72..99f91a7051a 100644 --- a/libgcc/config/s390/32/_fixsfdi.c +++ b/libgcc/config/s390/32/_fixsfdi.c @@ -26,13 +26,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef __s390x__ -#define EXP(fp) (((fp.l) >> 23) & 0xFF) -#define EXCESS 126 +#define EXPONENT_BIAS 127 +#define MANTISSA_BITS 23 +#define EXP(fp) (((fp.l) >> MANTISSA_BITS) & 0xFF) +#define PRECISION (MANTISSA_BITS + 1) #define SIGNBIT 0x80000000 #define SIGN(fp) ((fp.l) & SIGNBIT) -#define HIDDEN (1 << 23) +#define HIDDEN (1 << MANTISSA_BITS) #define MANT(fp) (((fp.l) & 0x7FFFFF) | HIDDEN) #define FRAC(fp) ((fp.l) & 0x7FFFFF) +#define LLONG_MAX 9223372036854775807LL +#define LLONG_MIN (-LLONG_MAX - 1LL) typedef int DItype_x __attribute__ ((mode (DI))); typedef unsigned int UDItype_x __attribute__ ((mode (DI))); @@ -45,6 +49,12 @@ union float_long USItype_x l; }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + DItype_x __fixsfdi (float a1); /* convert double to int */ @@ -58,32 +68,34 @@ __fixsfdi (float a1) fl1.f = a1; /* +/- 0, denormalized */ - if (!EXP (fl1)) return 0; - exp = EXP (fl1) - EXCESS - 24; + exp = EXP (fl1) - EXPONENT_BIAS - MANTISSA_BITS; /* number < 1 */ - - if (exp < -24) + if (exp <= -PRECISION) return 0; /* NaN */ - if ((EXP(fl1) == 0xff) && (FRAC(fl1) != 0)) /* NaN */ - return 0x8000000000000000ULL; + if ((EXP (fl1) == 0xff) && (FRAC (fl1) != 0)) /* NaN */ + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0x8000000000000000ULL; + } /* Number big number & +/- inf */ - - if (exp >= 40) { - l = (long long)1<<63; - if (!SIGN(fl1)) - l--; - return l; + if (exp >= 40) { + /* Don't throw an exception for -1p+63 */ + if (!SIGN (fl1) || exp > 40 || FRAC (fl1) != 0) + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return SIGN (fl1) ? LLONG_MIN : LLONG_MAX; } - l = MANT(fl1); + l = MANT (fl1); if (exp > 0) l <<= exp; diff --git a/libgcc/config/s390/32/_fixtfdi.c b/libgcc/config/s390/32/_fixtfdi.c index 50b6c9b46ac..de84972a22a 100644 --- a/libgcc/config/s390/32/_fixtfdi.c +++ b/libgcc/config/s390/32/_fixtfdi.c @@ -31,13 +31,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define MANTISSA_BITS 112 #define PRECISION (MANTISSA_BITS + 1) #define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.i[0]) & SIGNBIT) +#define SIGN(fp) ((fp.l.i[0]) & SIGNBIT) #define MANTD_HIGH_LL(fp) ((fp.ll[0] & HIGH_LL_FRAC_MASK) | HIGH_LL_UNIT_BIT) #define MANTD_LOW_LL(fp) (fp.ll[1]) #define FRACD_ZERO_P(fp) (!fp.ll[1] && !(fp.ll[0] & HIGH_LL_FRAC_MASK)) #define HIGH_LL_FRAC_BITS 48 #define HIGH_LL_UNIT_BIT ((UDItype_x)1 << HIGH_LL_FRAC_BITS) #define HIGH_LL_FRAC_MASK (HIGH_LL_UNIT_BIT - 1) +#define LLONG_MAX 9223372036854775807LL +#define LLONG_MIN (-LLONG_MAX - 1LL) typedef int DItype_x __attribute__ ((mode (DI))); typedef unsigned int UDItype_x __attribute__ ((mode (DI))); @@ -52,6 +54,12 @@ union double_long { UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + DItype_x __fixtfdi (long double a1); /* convert double to unsigned int */ @@ -79,7 +87,11 @@ __fixtfdi (long double a1) /* NaN: All exponent bits set and a nonzero fraction. */ if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) - return 0x8000000000000000ULL; + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0x8000000000000000ULL; + } /* One extra bit is needed for the unit bit which is appended by MANTD_HIGH_LL on the left of the matissa. */ @@ -92,13 +104,19 @@ __fixtfdi (long double a1) or more. */ if (exp >= 0) { - l = 1ULL << 63; /* long long min */ - return SIGND (dl1) ? l : l - 1; + /* Don't throw an exception for -1p+63 */ + if (!SIGN (dl1) + || exp > 0 + || MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) + || (dl1.ll[0] & HIGH_LL_FRAC_MASK)) + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return SIGN (dl1) ? LLONG_MIN : LLONG_MAX; } l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1)); - return SIGND (dl1) ? -(l >> -exp) : l >> -exp; + return SIGN (dl1) ? -(l >> -exp) : l >> -exp; } #endif /* !__s390x__ */ diff --git a/libgcc/config/s390/32/_fixunsdfdi.c b/libgcc/config/s390/32/_fixunsdfdi.c index 84cc8bc1a38..0a249611a23 100644 --- a/libgcc/config/s390/32/_fixunsdfdi.c +++ b/libgcc/config/s390/32/_fixunsdfdi.c @@ -27,9 +27,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef __s390x__ #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define EXCESSD 1022 +#define EXPONENT_BIAS 1023 +#define MANTISSA_BITS 52 +#define PRECISION (MANTISSA_BITS + 1) #define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) +#define SIGN(fp) ((fp.l.upper) & SIGNBIT) #define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) #define FRACD_LL(fp) (fp.ll & (HIDDEND_LL-1)) #define HIDDEND_LL ((UDItype_x)1 << 52) @@ -48,6 +50,12 @@ union double_long { UDItype_x ll; }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + UDItype_x __fixunsdfdi (double a1); /* convert double to unsigned int */ @@ -60,28 +68,44 @@ __fixunsdfdi (double a1) dl1.d = a1; - /* +/- 0, denormalized, negative */ - - if (!EXPD (dl1) || SIGND(dl1)) + /* +/- 0, denormalized */ + if (!EXPD (dl1)) return 0; - exp = EXPD (dl1) - EXCESSD - 53; + /* Negative. */ + if (SIGN (dl1)) + { + /* Value is <= -1.0 + C99 Annex F.4 requires an "invalid" exception to be thrown. */ + if (EXPD (dl1) >= EXPONENT_BIAS) + fexceptdiv (0.0, 0.0); + return 0; + } + + exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; /* number < 1 */ - if (exp < -53) + if (exp < -PRECISION) return 0; /* NaN */ if ((EXPD(dl1) == 0x7ff) && (FRACD_LL(dl1) != 0)) /* NaN */ - return 0x0ULL; + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0x0ULL; + } /* Number big number & + inf */ - if (exp >= 12) { - return 0xFFFFFFFFFFFFFFFFULL; - } + if (exp >= 12) + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0xFFFFFFFFFFFFFFFFULL; + } l = MANTD_LL(dl1); diff --git a/libgcc/config/s390/32/_fixunssfdi.c b/libgcc/config/s390/32/_fixunssfdi.c index aeb477a4ee8..7aeed28a0bd 100644 --- a/libgcc/config/s390/32/_fixunssfdi.c +++ b/libgcc/config/s390/32/_fixunssfdi.c @@ -26,11 +26,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef __s390x__ -#define EXP(fp) (((fp.l) >> 23) & 0xFF) -#define EXCESS 126 +#define EXPONENT_BIAS 127 +#define MANTISSA_BITS 23 +#define EXP(fp) (((fp.l) >> MANTISSA_BITS) & 0xFF) #define SIGNBIT 0x80000000 #define SIGN(fp) ((fp.l) & SIGNBIT) -#define HIDDEN (1 << 23) +#define HIDDEN (1 << MANTISSA_BITS) #define MANT(fp) (((fp.l) & 0x7FFFFF) | HIDDEN) #define FRAC(fp) ((fp.l) & 0x7FFFFF) @@ -45,6 +46,12 @@ union float_long USItype_x l; }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + UDItype_x __fixunssfdi (float a1); /* convert float to unsigned int */ @@ -57,30 +64,45 @@ __fixunssfdi (float a1) fl1.f = a1; - /* +/- 0, denormalized, negative */ - - if (!EXP (fl1) || SIGN(fl1)) + /* +/- 0, denormalized */ + if (!EXP (fl1)) return 0; - exp = EXP (fl1) - EXCESS - 24; + /* Negative. */ + if (SIGN (fl1)) + { + /* Value is <= -1.0 + C99 Annex F.4 requires an "invalid" exception to be thrown. */ + if (EXP (fl1) >= EXPONENT_BIAS) + fexceptdiv (0.0, 0.0); + return 0; + } + + exp = EXP (fl1) - EXPONENT_BIAS - MANTISSA_BITS; /* number < 1 */ - if (exp < -24) return 0; /* NaN */ - if ((EXP(fl1) == 0xff) && (FRAC(fl1) != 0)) /* NaN */ - return 0x0ULL; + if ((EXP (fl1) == 0xff) && (FRAC (fl1) != 0)) /* NaN */ + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0x0ULL; + } /* Number big number & + inf */ - if (exp >= 41) { - return 0xFFFFFFFFFFFFFFFFULL; - } + if (exp >= 41) + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0xFFFFFFFFFFFFFFFFULL; + } - l = MANT(fl1); + l = MANT (fl1); if (exp > 0) l <<= exp; diff --git a/libgcc/config/s390/32/_fixunstfdi.c b/libgcc/config/s390/32/_fixunstfdi.c index 0e2c61fb270..2f90a5f2f16 100644 --- a/libgcc/config/s390/32/_fixunstfdi.c +++ b/libgcc/config/s390/32/_fixunstfdi.c @@ -52,6 +52,12 @@ union double_long { UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ }; +static __inline__ void +fexceptdiv (float d, float e) +{ + __asm__ __volatile__ ("debr %0,%1" : : "f" (d), "f" (e) ); +} + UDItype_x __fixunstfdi (long double a1); /* convert double to unsigned int */ @@ -64,10 +70,20 @@ __fixunstfdi (long double a1) dl1.d = a1; - /* +/- 0, denormalized, negative */ - if (!EXPD (dl1) || SIGND(dl1)) + /* +/- 0, denormalized */ + if (!EXPD (dl1)) return 0; + /* Negative. */ + if (SIGND (dl1)) + { + /* Value is <= -1.0 + C99 Annex F.4 requires an "invalid" exception to be thrown. */ + if (EXPD (dl1) >= EXPONENT_BIAS) + fexceptdiv (0.0, 0.0); + return 0; + } + /* The exponent - considered the binary point at the right end of the mantissa. */ exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; @@ -80,16 +96,25 @@ __fixunstfdi (long double a1) /* NaN: All exponent bits set and a nonzero fraction. */ if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) - return 0x0ULL; + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0; + } /* One extra bit is needed for the unit bit which is appended by MANTD_HIGH_LL on the left of the matissa. */ exp += HIGH_LL_FRAC_BITS + 1; - /* If the result would still need a left shift it will be too large - to be represented. */ + /* If the result would still need a left shift it will be too + large to be represented. Infinities have all exponent bits set + and will end up here as well. */ if (exp > 0) - return 0xFFFFFFFFFFFFFFFFULL; + { + /* C99 Annex F.4 requires an "invalid" exception to be thrown. */ + fexceptdiv (0.0, 0.0); + return 0xFFFFFFFFFFFFFFFFULL; + } l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1));