]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
fold-const.c (add_double): Rename to add_double_with_sign.
authorEric Botcazou <ebotcazou@adacore.com>
Thu, 19 Oct 2006 20:25:18 +0000 (20:25 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 19 Oct 2006 20:25:18 +0000 (20:25 +0000)
* fold-const.c (add_double): Rename to add_double_with_sign.
Add 'unsigned_p' parameter and take it into account for the overflow.
(mul_double): Rename to mul_double_with_sign.
Add 'unsigned_p' parameter and take it into account for the overflow.
(fold_div_compare): Call add_double_with_sign instead of add_double
and mul_double_with_sign instead of mul_double, passing them the
unsignedness of the type.
* tree.h (add_double): Macroize.
(add_double_with_sign): New prototype.
(mul_double): Macroize.
(mul_double_with_sign): New prototype.

From-SVN: r117889

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/div-compare-1.c [new file with mode: 0644]
gcc/tree.h

index 0f66fe1dd420b7bc8b64de0042295f33a7df84f0..93afce20f70dbbfa31cf858dccd15ef412a98e5d 100644 (file)
@@ -1,3 +1,17 @@
+2006-10-19  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * fold-const.c (add_double): Rename to add_double_with_sign.
+       Add 'unsigned_p' parameter and take it into account for the overflow.
+       (mul_double): Rename to mul_double_with_sign. 
+       Add 'unsigned_p' parameter and take it into account for the overflow.
+       (fold_div_compare): Call add_double_with_sign instead of add_double
+       and mul_double_with_sign instead of mul_double, passing them the
+       unsignedness of the type.
+       * tree.h (add_double): Macroize.
+       (add_double_with_sign): New prototype.
+       (mul_double): Macroize.
+       (mul_double_with_sign): New prototype.
+
 2006-10-16  Richard Guenther  <rguenther@suse.de>
 
        PR target/25519
index 180fb35c66241279ffbb478e0880c71b2e197521..b254a9d79fc530dc99a23610805fa497bbc29a34 100644 (file)
@@ -285,14 +285,16 @@ force_fit_type (tree t, int overflowable,
 }
 \f
 /* Add two doubleword integers with doubleword result.
+   Return nonzero if the operation overflows according to UNSIGNED_P.
    Each argument is given as two `HOST_WIDE_INT' pieces.
    One argument is L1 and H1; the other, L2 and H2.
    The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV.  */
 
 int
-add_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
-           unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
-           unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+add_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+                     unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
+                     unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+                     bool unsigned_p)
 {
   unsigned HOST_WIDE_INT l;
   HOST_WIDE_INT h;
@@ -302,7 +304,11 @@ add_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
 
   *lv = l;
   *hv = h;
-  return OVERFLOW_SUM_SIGN (h1, h2, h);
+
+  if (unsigned_p)
+    return (unsigned HOST_WIDE_INT) h < (unsigned HOST_WIDE_INT) h1;
+  else
+    return OVERFLOW_SUM_SIGN (h1, h2, h);
 }
 
 /* Negate a doubleword integer with doubleword result.
@@ -329,15 +335,16 @@ neg_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
 }
 \f
 /* Multiply two doubleword integers with doubleword result.
-   Return nonzero if the operation overflows, assuming it's signed.
+   Return nonzero if the operation overflows according to UNSIGNED_P.
    Each argument is given as two `HOST_WIDE_INT' pieces.
    One argument is L1 and H1; the other, L2 and H2.
    The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV.  */
 
 int
-mul_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
-           unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
-           unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+                     unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
+                     unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+                     bool unsigned_p)
 {
   HOST_WIDE_INT arg1[4];
   HOST_WIDE_INT arg2[4];
@@ -368,11 +375,15 @@ mul_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
       prod[i + 4] = carry;
     }
 
-  decode (prod, lv, hv);       /* This ignores prod[4] through prod[4*2-1] */
-
-  /* Check for overflow by calculating the top half of the answer in full;
-     it should agree with the low half's sign bit.  */
+  decode (prod, lv, hv);
   decode (prod + 4, &toplow, &tophigh);
+
+  /* Unsigned overflow is immediate.  */
+  if (unsigned_p)
+    return (toplow | tophigh) != 0;
+
+  /* Check for signed overflow by calculating the signed representation of the
+     top half of the result; it should agree with the low half's sign bit.  */
   if (h1 < 0)
     {
       neg_double (l2, h2, &neglow, &neghigh);
@@ -5802,28 +5813,30 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
   tree arg01 = TREE_OPERAND (arg0, 1);
   unsigned HOST_WIDE_INT lpart;
   HOST_WIDE_INT hpart;
+  bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
   int overflow;
 
   /* We have to do this the hard way to detect unsigned overflow.
      prod = int_const_binop (MULT_EXPR, arg01, arg1, 0);  */
-  overflow = mul_double (TREE_INT_CST_LOW (arg01),
-                        TREE_INT_CST_HIGH (arg01),
-                        TREE_INT_CST_LOW (arg1),
-                        TREE_INT_CST_HIGH (arg1), &lpart, &hpart);
+  overflow = mul_double_with_sign (TREE_INT_CST_LOW (arg01),
+                                  TREE_INT_CST_HIGH (arg01),
+                                  TREE_INT_CST_LOW (arg1),
+                                  TREE_INT_CST_HIGH (arg1),
+                                  &lpart, &hpart, unsigned_p);
   prod = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
   prod = force_fit_type (prod, -1, overflow, false);
 
-  if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
+  if (unsigned_p)
     {
       tmp = int_const_binop (MINUS_EXPR, arg01, integer_one_node, 0);
       lo = prod;
 
       /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp, 0).  */
-      overflow = add_double (TREE_INT_CST_LOW (prod),
-                            TREE_INT_CST_HIGH (prod),
-                            TREE_INT_CST_LOW (tmp),
-                            TREE_INT_CST_HIGH (tmp),
-                            &lpart, &hpart);
+      overflow = add_double_with_sign (TREE_INT_CST_LOW (prod),
+                                      TREE_INT_CST_HIGH (prod),
+                                      TREE_INT_CST_LOW (tmp),
+                                      TREE_INT_CST_HIGH (tmp),
+                                      &lpart, &hpart, unsigned_p);
       hi = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
       hi = force_fit_type (hi, -1, overflow | TREE_OVERFLOW (prod),
                           TREE_CONSTANT_OVERFLOW (prod));
index 6f8a5e515748a589bc0c944f4c45f81bd4a8c3ac..4ee9b5c732c34373cc65af276a4111b08626ab2e 100644 (file)
@@ -1,3 +1,7 @@
+2006-10-19  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc.dg/div-compare-1.c: New test.
+
 2006-10-16  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        Backport:
diff --git a/gcc/testsuite/gcc.dg/div-compare-1.c b/gcc/testsuite/gcc.dg/div-compare-1.c
new file mode 100644 (file)
index 0000000..61adafe
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-std=c99" } */
+
+extern void abort(void);
+
+typedef unsigned long long uint64;
+
+int very_large_value (uint64 t)
+{
+  return (t / 1000000000ULL) > 9223372037ULL;
+}
+
+int main(void)
+{
+  uint64 t = 0xC000000000000000ULL;
+
+  if (!very_large_value (t))
+    abort ();
+
+  return 0;
+}
index 3ebad44518774c1f45c24d25f0e12e9723da1854..b3cb02dae62d66a2f43c7ad983b8950a77a131b2 100644 (file)
@@ -3499,14 +3499,20 @@ extern tree fold_abs_const (tree, tree);
 
 extern tree force_fit_type (tree, int, bool, bool);
 
-extern int add_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
-                      unsigned HOST_WIDE_INT, HOST_WIDE_INT,
-                      unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
+extern int add_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                unsigned HOST_WIDE_INT *, HOST_WIDE_INT *,
+                                bool);
+#define add_double(l1,h1,l2,h2,lv,hv) \
+  add_double_with_sign (l1, h1, l2, h2, lv, hv, false)
 extern int neg_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                       unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
-extern int mul_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
-                      unsigned HOST_WIDE_INT, HOST_WIDE_INT,
-                      unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
+extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                unsigned HOST_WIDE_INT *, HOST_WIDE_INT *,
+                                bool);
+#define mul_double(l1,h1,l2,h2,lv,hv) \
+  mul_double_with_sign (l1, h1, l2, h2, lv, hv, false)
 extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                           HOST_WIDE_INT, unsigned int,
                           unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, int);