Here is a new version of the patch not limited to NaNs and Infs
anymore.

Bootstrapped and regtested on s390 with various options.

-Andreas-

2014-02-06  Andreas Krebbel  <andreas.kreb...@de.ibm.com>

        * 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-06  Andreas Krebbel  <andreas.kreb...@de.ibm.com>

        * gcc.target/s390/fp2int1.c: New testcase.

commit 080f0a28fd6f27f5d122e287a6f18481d253d433
Author: Andreas Krebbel <kreb...@linux.vnet.ibm.com>
Date:   Wed Jan 29 10:13:51 2014 +0100

    S/390: libgcc: Throw INVALID exception for float->int conversions to
    implement C99 Annex F.4.

diff --git a/gcc/testsuite/gcc.target/s390/fp2int1.c 
b/gcc/testsuite/gcc.target/s390/fp2int1.c
new file mode 100644
index 0000000..2176370
--- /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 <stdlib.h>
+#include <stdio.h>
+#include <fenv.h>
+
+#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/config/s390/32/_fixdfdi.c b/libgcc/config/s390/32/_fixdfdi.c
index b1ba06d..e6dd4d1 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 dbf40b4..99f91a7 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 50b6c9b..de84972 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 84cc8bc..0a24961 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 aeb477a..7aeed28 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;
+      }
 
-    /* number < 1 */
+    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 0e2c61f..2f90a5f 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));

Reply via email to