re PR middle-end/50708 (Infinite loop between rshift_double and lshift_double if...
authorRichard Guenther <rguenther@suse.de>
Thu, 29 Mar 2012 08:27:04 +0000 (08:27 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 29 Mar 2012 08:27:04 +0000 (08:27 +0000)
2012-03-29  Richard Guenther  <rguenther@suse.de>

PR middle-end/50708
* double-int.h (rshift_double): Remove.
* double-int.c (lshift_double): Use absu_hwi to make count
positive.
(rshift_double): Make static, take unsigned count argument,
remove handling of negative count argument.
(double_int_rshift): Dispatch to lshift_double.

From-SVN: r185951

gcc/ChangeLog
gcc/double-int.c
gcc/double-int.h

index e988df5..0c2d199 100644 (file)
@@ -1,3 +1,13 @@
+2012-03-29  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/50708
+       * double-int.h (rshift_double): Remove.
+       * double-int.c (lshift_double): Use absu_hwi to make count
+       positive.
+       (rshift_double): Make static, take unsigned count argument,
+       remove handling of negative count argument.
+       (double_int_rshift): Dispatch to lshift_double.
+
 2012-03-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/biarch64.h (TARGET_64BIT_DEFAULT): Add
index 834eaf9..0f95442 100644 (file)
@@ -186,24 +186,22 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
   return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0;
 }
 
-/* Shift the doubleword integer in L1, H1 left by COUNT places
-   keeping only PREC bits of result.
-   Shift right if COUNT is negative.
-   ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
+/* Shift the doubleword integer in L1, H1 right by COUNT places
+   keeping only PREC bits of result.  ARITH nonzero specifies
+   arithmetic shifting; otherwise use logical shift.
    Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV.  */
 
-void
-lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
-              HOST_WIDE_INT count, unsigned int prec,
-              unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
+static void
+rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+              unsigned HOST_WIDE_INT count, unsigned int prec,
+              unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+              bool arith)
 {
   unsigned HOST_WIDE_INT signmask;
 
-  if (count < 0)
-    {
-      rshift_double (l1, h1, -count, prec, lv, hv, arith);
-      return;
-    }
+  signmask = (arith
+             ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
+             : 0);
 
   if (SHIFT_COUNT_TRUNCATED)
     count %= prec;
@@ -217,61 +215,58 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
     }
   else if (count >= HOST_BITS_PER_WIDE_INT)
     {
-      *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);
-      *lv = 0;
+      *hv = 0;
+      *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
     }
   else
     {
-      *hv = (((unsigned HOST_WIDE_INT) h1 << count)
-            | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
-      *lv = l1 << count;
+      *hv = (unsigned HOST_WIDE_INT) h1 >> count;
+      *lv = ((l1 >> count)
+            | ((unsigned HOST_WIDE_INT) h1
+               << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
     }
 
-  /* Sign extend all bits that are beyond the precision.  */
-
-  signmask = -((prec > HOST_BITS_PER_WIDE_INT
-               ? ((unsigned HOST_WIDE_INT) *hv
-                  >> (prec - HOST_BITS_PER_WIDE_INT - 1))
-               : (*lv >> (prec - 1))) & 1);
+  /* Zero / sign extend all bits that are beyond the precision.  */
 
-  if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
+  if (count >= (HOST_WIDE_INT)prec)
+    {
+      *hv = signmask;
+      *lv = signmask;
+    }
+  else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT)
     ;
-  else if (prec >= HOST_BITS_PER_WIDE_INT)
+  else if ((prec - count) >= HOST_BITS_PER_WIDE_INT)
     {
-      *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
-      *hv |= signmask << (prec - 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);
-      *lv |= signmask << prec;
+      *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count));
+      *lv |= signmask << (prec - count);
     }
 }
 
-/* Shift the doubleword integer in L1, H1 right by COUNT places
-   keeping only PREC bits of result.  Shift left if COUNT is negative.
+/* Shift the doubleword integer in L1, H1 left by COUNT places
+   keeping only PREC bits of result.
+   Shift right if COUNT is negative.
    ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
    Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV.  */
 
 void
-rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
               HOST_WIDE_INT count, unsigned int prec,
-              unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
-              bool arith)
+              unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
 {
   unsigned HOST_WIDE_INT signmask;
 
   if (count < 0)
     {
-      lshift_double (l1, h1, -count, prec, lv, hv, arith);
+      rshift_double (l1, h1, absu_hwi (count), prec, lv, hv, arith);
       return;
     }
 
-  signmask = (arith
-             ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
-             : 0);
-
   if (SHIFT_COUNT_TRUNCATED)
     count %= prec;
 
@@ -284,36 +279,35 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
     }
   else if (count >= HOST_BITS_PER_WIDE_INT)
     {
-      *hv = 0;
-      *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
+      *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);
+      *lv = 0;
     }
   else
     {
-      *hv = (unsigned HOST_WIDE_INT) h1 >> count;
-      *lv = ((l1 >> count)
-            | ((unsigned HOST_WIDE_INT) h1
-               << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
+      *hv = (((unsigned HOST_WIDE_INT) h1 << count)
+            | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
+      *lv = l1 << count;
     }
 
-  /* Zero / sign extend all bits that are beyond the precision.  */
+  /* 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)
+  signmask = -((prec > HOST_BITS_PER_WIDE_INT
+               ? ((unsigned HOST_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 - count) >= HOST_BITS_PER_WIDE_INT)
+  else if (prec >= 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);
+      *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 - count));
-      *lv |= signmask << (prec - count);
+      *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
+      *lv |= signmask << prec;
     }
 }
 
@@ -895,7 +889,7 @@ double_int
 double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith)
 {
   double_int ret;
-  rshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith);
+  lshift_double (a.low, a.high, -count, prec, &ret.low, &ret.high, arith);
   return ret;
 }
 
index 6d15551..408ed92 100644 (file)
@@ -300,9 +300,6 @@ extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
 extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                           HOST_WIDE_INT, unsigned int,
                           unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool);
-extern void rshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
-                          HOST_WIDE_INT, unsigned int,
-                          unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool);
 extern int div_and_round_double (unsigned, int, unsigned HOST_WIDE_INT,
                                 HOST_WIDE_INT, unsigned HOST_WIDE_INT,
                                 HOST_WIDE_INT, unsigned HOST_WIDE_INT *,