This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch to fix lshift_double and rshift_double prec handling


The lshift_double and rshift_double PREC argument is documented as
controlling the number of bits in the result.  Unfortunately they
don't actually contain any code to implement this.

Consider using rshift_double to perform a logical shift right of
QImode -4.

  l1          h1          count  prec             *lv         *hv
  0xfffffffc  0xffffffff  1      8    produces    0xfffffffe  0x7fffffff

                                      instead of  0x0000007e  0x00000000

Or using rrotate_double (which uses rshift_double) to rotate QImode -4:

  0xfffffffc  0xffffffff  1      8    produces    0xfffffffe  0xffffffff

                                      instead of  0x0000007e  0x00000000

simplify_binary_operation, lrotate_double, and rrotate_double all seem
to expect PREC to be honored (which it currently isn't).

This patch passes make bootstrap and make check on Dec Alpha 4.0f
and Solaris 7 x86.

ChangeLog:

Wed Nov  7 16:20:32 EST 2001  John Wehle  (john@feith.com)

	* fold-const.c (lshift_double): Honor PREC.
	(rshift_double): Likewise.

Enjoy!

-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/fold-const.c.ORIGINAL	Wed Nov  7 12:00:14 2001
--- gcc/fold-const.c	Wed Nov  7 16:59:42 2001
*************** lshift_double (l1, h1, count, prec, lv, 
*** 383,388 ****
--- 383,390 ----
       HOST_WIDE_INT *hv;
       int arith;
  {
+   unsigned HOST_WIDE_INT signmask;
+ 
    if (count < 0)
      {
        rshift_double (l1, h1, -count, prec, lv, hv, arith);
*************** lshift_double (l1, h1, count, prec, lv, 
*** 412,417 ****
--- 414,439 ----
  	     | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
        *lv = l1 << count;
      }
+ 
+   /* Sign extend all bits that are beyond the precision.  */
+ 
+   signmask = -((prec > HOST_BITS_PER_WIDE_INT
+ 		? (*hv >> (prec - HOST_BITS_PER_WIDE_INT - 1))
+ 		: (*lv >> (prec - 1))) & 1);
+ 
+   if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
+     ;
+   else if (prec >= HOST_BITS_PER_WIDE_INT)
+     {
+       *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+       *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT);
+     }
+   else
+     {
+       *hv = signmask;
+       *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
+       *lv |= signmask << prec;
+     }
  }
  
  /* Shift the doubleword integer in L1, H1 right by COUNT places
*************** void
*** 423,429 ****
  rshift_double (l1, h1, count, prec, lv, hv, arith)
       unsigned HOST_WIDE_INT l1;
       HOST_WIDE_INT h1, count;
!      unsigned int prec ATTRIBUTE_UNUSED;
       unsigned HOST_WIDE_INT *lv;
       HOST_WIDE_INT *hv;
       int arith;
--- 445,451 ----
  rshift_double (l1, h1, count, prec, lv, hv, arith)
       unsigned HOST_WIDE_INT l1;
       HOST_WIDE_INT h1, count;
!      unsigned int prec;
       unsigned HOST_WIDE_INT *lv;
       HOST_WIDE_INT *hv;
       int arith;
*************** rshift_double (l1, h1, count, prec, lv, 
*** 443,463 ****
      {
        /* Shifting by the host word size is undefined according to the
  	 ANSI standard, so we must handle this as a special case.  */
!       *hv = signmask;
!       *lv = signmask;
      }
    else if (count >= HOST_BITS_PER_WIDE_INT)
      {
!       *hv = signmask;
!       *lv = ((signmask << (2 * HOST_BITS_PER_WIDE_INT - count - 1) << 1)
! 	     | ((unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT)));
      }
    else
      {
        *lv = ((l1 >> count)
  	     | ((unsigned HOST_WIDE_INT) h1 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
!       *hv = ((signmask << (HOST_BITS_PER_WIDE_INT - count))
! 	     | ((unsigned HOST_WIDE_INT) h1 >> count));
      }
  }
  
--- 465,504 ----
      {
        /* Shifting by the host word size is undefined according to the
  	 ANSI standard, so we must handle this as a special case.  */
!       *hv = 0;
!       *lv = 0;
      }
    else if (count >= HOST_BITS_PER_WIDE_INT)
      {
!       *hv = 0;
!       *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
      }
    else
      {
+       *hv = (unsigned HOST_WIDE_INT) h1 >> count;
        *lv = ((l1 >> count)
  	     | ((unsigned HOST_WIDE_INT) h1 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
!     }
! 
!   /* Zero / sign extend all bits that are beyond the precision.  */
! 
!   if (count >= (HOST_WIDE_INT)prec)
!     {
!       *hv = signmask;
!       *lv = signmask;
!     }
!   else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT)
!     ;
!   else if ((prec - count) >= HOST_BITS_PER_WIDE_INT)
!     {
!       *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT));
!       *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT);
!     }
!   else
!     {
!       *hv = signmask;
!       *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count));
!       *lv |= signmask << (prec - count);
      }
  }
  
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]