From 393c005884c547ee6d4cebb2fb938e6214714e9e Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Wed, 30 Jan 2008 08:00:51 +0000 Subject: [PATCH] fixdfdi.h (__fixunstfdi, __fixtfdi): Rearrange the overflow check to make it easier to read. 2008-01-30 Andreas Krebbel * config/s390/fixdfdi.h (__fixunstfdi, __fixtfdi): Rearrange the overflow check to make it easier to read. (__fixtfdi): Change the type of the ll member in union long_double to UDItype_x. 2008-01-30 Andreas Krebbel * gcc.target/s390/tf_to_di-1.c: New testcase. From-SVN: r131957 --- gcc/ChangeLog | 7 ++++ gcc/config/s390/fixdfdi.h | 34 +++++++++------- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.target/s390/tf_to_di-1.c | 46 ++++++++++++++++++++++ 4 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/tf_to_di-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 450214646c1..176a1372e66 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2008-01-30 Andreas Krebbel + + * config/s390/fixdfdi.h (__fixunstfdi, __fixtfdi): Rearrange + the overflow check to make it easier to read. + (__fixtfdi): Change the type of the ll member in union + long_double to UDItype_x. + 2008-01-30 Jakub Jelinek PR middle-end/34969 diff --git a/gcc/config/s390/fixdfdi.h b/gcc/config/s390/fixdfdi.h index f3e48ac8f9d..865bf46b99f 100644 --- a/gcc/config/s390/fixdfdi.h +++ b/gcc/config/s390/fixdfdi.h @@ -77,13 +77,15 @@ __fixunstfdi (long double a1) if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) return 0x0ULL; - /* If the upper ll part of the mantissa isn't - zeroed out after shifting the number would be to large. */ - if (exp >= -HIGH_LL_FRAC_BITS) - return 0xFFFFFFFFFFFFFFFFULL; - + /* 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 (exp > 0) + return 0xFFFFFFFFFFFFFFFFULL; + l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1)); @@ -117,7 +119,7 @@ union double_long { struct { SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */ } l; - DItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ + UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ }; DItype_x __fixtfdi (long double a1); @@ -136,7 +138,7 @@ __fixtfdi (long double a1) if (!EXPD (dl1)) return 0; - /* The exponent - considered the binary point at the right end of + /* The exponent - considered the binary point at the right end of the mantissa. */ exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; @@ -149,17 +151,21 @@ __fixtfdi (long double a1) if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) return 0x8000000000000000ULL; - /* If the upper ll part of the mantissa isn't - zeroed out after shifting the number would be to large. */ - if (exp >= -HIGH_LL_FRAC_BITS) + /* 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. Compared to the unsigned variant we have to + take care that there is still space for the sign bit to be + applied. So we can only go on if there is a right-shift by one + or more. */ + if (exp >= 0) { - l = (long long)1 << 63; /* long int min */ + l = 1ULL << 63; /* long long min */ return SIGND (dl1) ? l : l - 1; } - /* The extra bit is needed for the sign bit. */ - exp += HIGH_LL_FRAC_BITS + 1; - l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9c218875da7..3cee20a403c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-01-30 Andreas Krebbel + + * gcc.target/s390/tf_to_di-1.c: New testcase. + 2008-01-30 Paul Thomas PR fortran/34975 diff --git a/gcc/testsuite/gcc.target/s390/tf_to_di-1.c b/gcc/testsuite/gcc.target/s390/tf_to_di-1.c new file mode 100644 index 00000000000..d79e6f3502e --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/tf_to_di-1.c @@ -0,0 +1,46 @@ +/* { dg-options "-O0 -mlong-double-128" } */ + +#include +#include + +void +check_ll (long double ld, long long ll) +{ + if ((long long)ld != ll) + { + printf ("ld: %Lf expect: %lld result: %lld\n", + ld, ll, (long long)ld); + abort (); + } +} + +void +check_ull (long double ld, unsigned long long ull) +{ + if ((unsigned long long)ld != ull) + { + printf ("ld: %Lf expect: %llu result: %llu\n", + ld, ull, (unsigned long long)ld); + abort (); + } +} + +int +main () +{ + const long long ll_max = (long long)((1ULL << 63) - 1); + const long long ll_min = -ll_max - 1; + + check_ll (206.23253, 206LL); + check_ull (206.23253, 206ULL); + check_ll ((long double)ll_max, ll_max); + check_ull ((long double)ll_max, ll_max); + check_ll ((long double)ll_min, ll_min); + check_ll (0.0, 0); + check_ull (0.0, 0); + check_ll (-1.0, -1); + check_ll ((long double)0xffffffffffffffffULL, ll_max); + check_ull ((long double)0xffffffffffffffffULL, 0xffffffffffffffffULL); + + return 0; +}