OSDN Git Service

2006-10-28 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Oct 2006 18:03:21 +0000 (18:03 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Oct 2006 18:03:21 +0000 (18:03 +0000)
PR middle-end/26899
* fold-const.c (maybe_canonicalize_comparison_1): Helper
for maybe_canonicalize_comparison.
(maybe_canonicalize_comparison): New function for canonicalizing
comparison trees.
(fold_comparison): Call it to canonicalize comparisons with
constants involved.

* gcc.dg/tree-ssa/pr26899.c: New testcase.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118106 138bc75d-0d04-0410-961f-82ee72b054a4

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

index e64b3f4..fe590bf 100644 (file)
@@ -1,5 +1,15 @@
 2006-10-28  Richard Guenther  <rguenther@suse.de>
 
+       PR middle-end/26899
+       * fold-const.c (maybe_canonicalize_comparison_1): Helper
+       for maybe_canonicalize_comparison.
+       (maybe_canonicalize_comparison): New function for canonicalizing
+       comparison trees.
+       (fold_comparison): Call it to canonicalize comparisons with
+       constants involved.
+
+2006-10-28  Richard Guenther  <rguenther@suse.de>
+
        PR target/28806
        * builtins.c (expand_builtin_int_roundingfn_2): Expand
        BUILT_IN_LROUND and BUILT_IN_LLROUND from here.
index 571a7e8..32e64c9 100644 (file)
@@ -7749,6 +7749,126 @@ fold_minmax (enum tree_code code, tree type, tree op0, tree op1)
   return NULL_TREE;
 }
 
+/* Helper that tries to canonicalize the comparison ARG0 CODE ARG1
+   by changing CODE to reduce the magnitude of constants involved in
+   ARG0 of the comparison.
+   Returns a canonicalized comparison tree if a simplification was
+   possible, otherwise returns NULL_TREE.  */
+
+static tree
+maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
+                                tree arg0, tree arg1)
+{
+  enum tree_code code0 = TREE_CODE (arg0);
+  tree t, cst0 = NULL_TREE;
+  int sgn0;
+  bool swap = false;
+
+  /* Match A +- CST code arg1 and CST code arg1.  */
+  if (!(((code0 == MINUS_EXPR
+          || code0 == PLUS_EXPR)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       || code0 == INTEGER_CST))
+    return NULL_TREE;
+
+  /* Identify the constant in arg0 and its sign.  */
+  if (code0 == INTEGER_CST)
+    cst0 = arg0;
+  else
+    cst0 = TREE_OPERAND (arg0, 1);
+  sgn0 = tree_int_cst_sgn (cst0);
+
+  /* Overflowed constants and zero will cause problems.  */
+  if (integer_zerop (cst0)
+      || TREE_OVERFLOW (cst0))
+    return NULL_TREE;
+
+  /* See if we can reduce the mangitude of the constant in
+     arg0 by changing the comparison code.  */
+  if (code0 == INTEGER_CST)
+    {
+      /* CST <= arg1  ->  CST-1 < arg1.  */
+      if (code == LE_EXPR && sgn0 == 1)
+       code = LT_EXPR;
+      /* -CST < arg1  ->  -CST-1 <= arg1.  */
+      else if (code == LT_EXPR && sgn0 == -1)
+       code = LE_EXPR;
+      /* CST > arg1  ->  CST-1 >= arg1.  */
+      else if (code == GT_EXPR && sgn0 == 1)
+       code = GE_EXPR;
+      /* -CST >= arg1  ->  -CST-1 > arg1.  */
+      else if (code == GE_EXPR && sgn0 == -1)
+       code = GT_EXPR;
+      else
+        return NULL_TREE;
+      /* arg1 code' CST' might be more canonical.  */
+      swap = true;
+    }
+  else
+    {
+      /* A - CST < arg1  ->  A - CST-1 <= arg1.  */
+      if (code == LT_EXPR
+         && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+       code = LE_EXPR;
+      /* A + CST > arg1  ->  A + CST-1 >= arg1.  */
+      else if (code == GT_EXPR
+              && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+       code = GE_EXPR;
+      /* A + CST <= arg1  ->  A + CST-1 < arg1.  */
+      else if (code == LE_EXPR
+              && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+       code = LT_EXPR;
+      /* A - CST >= arg1  ->  A - CST-1 > arg1.  */
+      else if (code == GE_EXPR
+              && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+       code = GT_EXPR;
+      else
+       return NULL_TREE;
+    }
+
+  /* Now build the constant reduced in magnitude.  */
+  t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR,
+                      cst0, build_int_cst (TREE_TYPE (cst0), 1), 0);
+  if (code0 != INTEGER_CST)
+    t = fold_build2 (code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
+
+  /* If swapping might yield to a more canonical form, do so.  */
+  if (swap)
+    return fold_build2 (swap_tree_comparison (code), type, arg1, t);
+  else
+    return fold_build2 (code, type, t, arg1);
+}
+
+/* Canonicalize the comparison ARG0 CODE ARG1 with type TYPE with undefined
+   overflow further.  Try to decrease the magnitude of constants involved
+   by changing LE_EXPR and GE_EXPR to LT_EXPR and GT_EXPR or vice versa
+   and put sole constants at the second argument position.
+   Returns the canonicalized tree if changed, otherwise NULL_TREE.  */
+
+static tree
+maybe_canonicalize_comparison (enum tree_code code, tree type,
+                              tree arg0, tree arg1)
+{
+  tree t;
+
+  /* In principle pointers also have undefined overflow behavior,
+     but that causes problems elsewhere.  */
+  if ((flag_wrapv || flag_trapv)
+      || (TYPE_UNSIGNED (TREE_TYPE (arg0))
+         && !POINTER_TYPE_P (TREE_TYPE (arg0))))
+    return NULL_TREE;
+
+  /* Try canonicalization by simplifying arg0.  */
+  t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1);
+  if (t)
+    return t;
+
+  /* Try canonicalization by simplifying arg1 using the swapped
+     comparsion.  */
+  code = swap_tree_comparison (code);
+  return maybe_canonicalize_comparison_1 (code, type, arg1, arg0);
+}
+
 /* Subroutine of fold_binary.  This routine performs all of the
    transformations that are common to the equality/inequality
    operators (EQ_EXPR and NE_EXPR) and the ordering operators
@@ -7877,6 +7997,10 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
                            variable2);
     }
 
+  tem = maybe_canonicalize_comparison (code, type, arg0, arg1);
+  if (tem)
+    return tem;
+
   if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
     {
       tree targ0 = strip_float_extensions (arg0);
index 8f5a435..e2096ba 100644 (file)
@@ -1,5 +1,10 @@
 2006-10-28  Richard Guenther  <rguenther@suse.de>
 
+       PR middle-end/26899
+       * gcc.dg/tree-ssa/pr26899.c: New testcase.
+
+2006-10-28  Richard Guenther  <rguenther@suse.de>
+
        PR target/28806
        * gcc.target/i386/math-torture/lround.c: New testcase.
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr26899.c b/gcc/testsuite/gcc.dg/tree-ssa/pr26899.c
new file mode 100644 (file)
index 0000000..5e19f56
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-options "-fdump-tree-gimple" } */
+
+int foo (int i, int j)
+{
+  return (i < j + 1) || (j > i - 1);
+}
+
+/* { dg-final { scan-tree-dump "j >= i" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
+