[PATCH] S/390: Fix problem with fixtfdi on 31 bit

Andreas Krebbel Andreas.Krebbel@de.ibm.com
Tue Jan 22 19:27:00 GMT 2008


Hello,

the attached patch fixes a problem with TF to DImode conversion on
31bit.

Bootstrapped on s390 and s390x with GCC 4.1 and mainline.
No testsuite regressions.

OK for 4.1, 4.2 and mainline?

The testcase will be put into the gcc.dg directory for 4.1 and 4.2
since the s390 directory has been introduced for 4.3.

Bye,

-Andreas-

2008-01-22  Andreas Krebbel  <krebbel1@de.ibm.com>

	* 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.


Index: gcc/config/s390/fixdfdi.h
===================================================================
*** gcc/config/s390/fixdfdi.h.orig	2008-01-18 15:32:13.000000000 +0100
--- gcc/config/s390/fixdfdi.h	2008-01-22 10:24:17.000000000 +0100
*************** __fixunstfdi (long double a1)
*** 77,89 ****
      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;
! 
      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));
  
--- 77,91 ----
      if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1))
        return 0x0ULL;
  
!     /* 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 to 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));
  
*************** union double_long {
*** 117,123 ****
    struct {
        SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */
      } l;
!   DItype_x ll[2];   /* 64 bit parts: 0 upper, 1 lower */
  };
  
  DItype_x __fixtfdi (long double a1);
--- 119,125 ----
    struct {
        SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */
      } l;
!   UDItype_x ll[2];   /* 64 bit parts: 0 upper, 1 lower */
  };
  
  DItype_x __fixtfdi (long double a1);
*************** __fixtfdi (long double a1)
*** 136,142 ****
      if (!EXPD (dl1))
        return 0;
  
!     /* The exponent - considered the binary point at the right end of 
         the mantissa.  */
      exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS;
  
--- 138,144 ----
      if (!EXPD (dl1))
        return 0;
  
!     /* The exponent - considered the binary point at the right end of
         the mantissa.  */
      exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS;
  
*************** __fixtfdi (long double a1)
*** 149,165 ****
      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)
        {
! 	l = (long long)1 << 63; /* long int 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));
  
--- 151,171 ----
      if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1))
        return 0x8000000000000000ULL;
  
!     /* 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 to 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 long int min */
  	return SIGND (dl1) ? l : l - 1;
        }
  
      l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1)
          | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1));
  
Index: gcc/testsuite/gcc.target/s390/tf_to_di-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.target/s390/tf_to_di-1.c	2008-01-22 10:18:25.000000000 +0100
***************
*** 0 ****
--- 1,46 ----
+ /* { dg-options "-O0 -mlong-double-128" } */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ 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;
+ }



More information about the Gcc-patches mailing list