re PR middle-end/61045 (Wrong constant folding)
authorRichard Biener <rguenther@suse.de>
Wed, 28 May 2014 12:44:11 +0000 (12:44 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 28 May 2014 12:44:11 +0000 (12:44 +0000)
2014-05-28  Richard Biener  <rguenther@suse.de>

PR middle-end/61045
* fold-const.c (fold_comparison): When folding
X +- C1 CMP Y +- C2 to X CMP Y +- C2 +- C1 also ensure
the sign of the remaining constant operand stays the same.

* gcc.dg/pr61045.c: New testcase.

From-SVN: r211018

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr61045.c [new file with mode: 0644]

index 2fed7e80fec5d6ccb3425cc5d1af44405de34bab..76d4a66f3226a70851371f00f1439e5252435e72 100644 (file)
@@ -1,3 +1,10 @@
+2014-05-28  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61045
+       * fold-const.c (fold_comparison): When folding
+       X +- C1 CMP Y +- C2 to X CMP Y +- C2 +- C1 also ensure
+       the sign of the remaining constant operand stays the same.
+
 2014-05-28  Kaushik Phatak  <kaushik.phatak@kpit.com>
 
        * config/rl78/rl78.h (TARGET_CPU_CPP_BUILTINS): Define
index b3009340e3ec202058b0ae3c79added67058ac65..0451b6a90beea7b12624003cebffb0b592ddb8be 100644 (file)
@@ -9239,7 +9239,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
   /* Transform comparisons of the form X +- C1 CMP Y +- C2 to
      X CMP Y +- C2 +- C1 for signed X, Y.  This is valid if
      the resulting offset is smaller in absolute value than the
-     original one.  */
+     original one and has the same sign.  */
   if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
       && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
       && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
@@ -9258,32 +9258,35 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
                                      "a comparison");
 
       /* Put the constant on the side where it doesn't overflow and is
-        of lower absolute value than before.  */
+        of lower absolute value and of same sign than before.  */
       cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
                             ? MINUS_EXPR : PLUS_EXPR,
                             const2, const1);
       if (!TREE_OVERFLOW (cst)
-         && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
+         && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2)
+         && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const2))
        {
          fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
          return fold_build2_loc (loc, code, type,
-                             variable1,
-                             fold_build2_loc (loc,
-                                          TREE_CODE (arg1), TREE_TYPE (arg1),
-                                          variable2, cst));
+                                 variable1,
+                                 fold_build2_loc (loc, TREE_CODE (arg1),
+                                                  TREE_TYPE (arg1),
+                                                  variable2, cst));
        }
 
       cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
                             ? MINUS_EXPR : PLUS_EXPR,
                             const1, const2);
       if (!TREE_OVERFLOW (cst)
-         && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
+         && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1)
+         && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const1))
        {
          fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
          return fold_build2_loc (loc, code, type,
-                             fold_build2_loc (loc, TREE_CODE (arg0), TREE_TYPE (arg0),
-                                          variable1, cst),
-                             variable2);
+                                 fold_build2_loc (loc, TREE_CODE (arg0),
+                                                  TREE_TYPE (arg0),
+                                                  variable1, cst),
+                                 variable2);
        }
     }
 
index ad6490ab48f3a17f3f7321ba7fae5b38d9650925..ab4641343a3cbdf790d0758d5c33bd4e80613b4b 100644 (file)
@@ -1,3 +1,8 @@
+2014-05-28  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61045
+       * gcc.dg/pr61045.c: New testcase.
+
 2014-05-28  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * lib/clearcap.exp: New file.
diff --git a/gcc/testsuite/gcc.dg/pr61045.c b/gcc/testsuite/gcc.dg/pr61045.c
new file mode 100644 (file)
index 0000000..1808cdc
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+/* { dg-options "-fstrict-overflow" } */
+
+int main ()
+{
+  int a = 0;
+  int b = __INT_MAX__;
+  int t = (a - 2) > (b - 1);
+  if (t != 0)
+    __builtin_abort();
+  return 0;
+}