re PR middle-end/26898 (Fold does not fold signed + CST1 CMP signed + CST2)
authorRichard Guenther <rguenther@suse.de>
Sat, 21 Oct 2006 13:21:06 +0000 (13:21 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 21 Oct 2006 13:21:06 +0000 (13:21 +0000)
2006-10-21  Richard Guenther  <rguenther@suse.de>

PR middle-end/26898
* fold-const.c (fold_comparison): Fold signed comparisons
of the form X +- C1 CMP Y +- C2.

* gcc.dg/torture/pr26898-1.c: New testcase.
* gcc.dg/torture/pr26898-2.c: Likewise.

From-SVN: r117931

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr26898-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr26898-2.c [new file with mode: 0644]

index 0bb59aab9b185909a59637596a147a4cff1cf092..fdaa244cfe58e0cec1328147b702ff7bd1d0105f 100644 (file)
@@ -1,3 +1,9 @@
+2006-10-21  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/26898
+       * fold-const.c (fold_comparison): Fold signed comparisons
+       of the form X +- C1 CMP Y +- C2.
+
 2006-10-21  Richard Guenther  <rguenther@suse.de>
 
        PR target/19116
index 30efccd7ea74a8d07c7fc4ebf027befc7cf8b29d..b04022e1086eac4b548996fc6f62d57a650c5828 100644 (file)
@@ -7835,6 +7835,48 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
        }
     }
 
+  /* 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.  */
+  if (!(flag_wrapv || flag_trapv)
+      && !TYPE_UNSIGNED (TREE_TYPE (arg0))
+      && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+      && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)))
+      && (TREE_CODE (arg1) == PLUS_EXPR || TREE_CODE (arg1) == MINUS_EXPR)
+      && (TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
+         && !TREE_OVERFLOW (TREE_OPERAND (arg1, 1))))
+    {
+      tree const1 = TREE_OPERAND (arg0, 1);
+      tree const2 = TREE_OPERAND (arg1, 1);
+      tree variable1 = TREE_OPERAND (arg0, 0);
+      tree variable2 = TREE_OPERAND (arg1, 0);
+      tree cst;
+
+      /* Put the constant on the side where it doesn't overflow and is
+        of lower absolute value than before.  */
+      cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
+                            ? MINUS_EXPR : PLUS_EXPR,
+                            const2, const1, 0);
+      if (!TREE_OVERFLOW (cst)
+         && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
+       return fold_build2 (code, type,
+                           variable1,
+                           fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1),
+                                        variable2, cst));
+
+      cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
+                            ? MINUS_EXPR : PLUS_EXPR,
+                            const1, const2, 0);
+      if (!TREE_OVERFLOW (cst)
+         && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
+       return fold_build2 (code, type,
+                           fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0),
+                                        variable1, cst),
+                           variable2);
+    }
+
   if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
     {
       tree targ0 = strip_float_extensions (arg0);
index 8634b8e41ec32b2e0398b942ef63b38c783393ad..55d336cc162cd5789818b0c01e22b48404b2f8f3 100644 (file)
@@ -1,3 +1,9 @@
+2006-10-21  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/26898
+       * gcc.dg/torture/pr26898-1.c: New testcase.
+       * gcc.dg/torture/pr26898-2.c: Likewise.
+
 2006-10-20  Lee Millward  <lee.millward@codesourcery.com>
         
         PR c++/28053
diff --git a/gcc/testsuite/gcc.dg/torture/pr26898-1.c b/gcc/testsuite/gcc.dg/torture/pr26898-1.c
new file mode 100644 (file)
index 0000000..12ca1f3
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do link } */
+
+#include <limits.h>
+
+extern void link_error(void);
+int main()
+{
+  int i0, i1;
+  if (!(i0 + 1 < i1 + 1 == i0 < i1))
+    link_error ();
+  if (!(i0 + INT_MIN < i1 - INT_MAX == i0 < i1 - -1))
+    link_error ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr26898-2.c b/gcc/testsuite/gcc.dg/torture/pr26898-2.c
new file mode 100644 (file)
index 0000000..508fde4
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+
+#include <limits.h>
+
+int a = 0, b = INT_MAX - 1;
+extern void abort(void);
+int main()
+{
+  if (a - 1 > b + 1)
+    abort();
+  return 0;
+}