re PR tree-optimization/18431 (Code for arrays and pointers are not the same)
authorZdenek Dvorak <dvorakz@suse.cz>
Mon, 15 Nov 2004 00:18:37 +0000 (01:18 +0100)
committerZdenek Dvorak <rakdver@gcc.gnu.org>
Mon, 15 Nov 2004 00:18:37 +0000 (00:18 +0000)
PR tree-optimization/18431
* fold-const.c (associate_trees): Do not produce x + 0.
(fold_widened_comparison, fold_sign_changed_comparison): New functions.
(fold): Use them.
* tree-ssa-loop-niter.c (upper_bound_in_type, lower_bound_in_type):
Moved ...
* tree.c (upper_bound_in_type, lower_bound_in_type): Here.
* tree.h (upper_bound_in_type, lower_bound_in_type): Declare.

* testsuite/gcc.c-torture/execute/20041114-1.c: New test.

From-SVN: r90646

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20041114-1.c [new file with mode: 0644]
gcc/tree-ssa-loop-niter.c
gcc/tree.c
gcc/tree.h

index 84cd2b0d38df51775fba3b25d5d3d9eb09dcdb77..c26b57c832d615e0f531f10fe2561bc883cc87e9 100644 (file)
@@ -1,3 +1,14 @@
+2004-11-14  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       PR tree-optimization/18431
+       * fold-const.c (associate_trees): Do not produce x + 0.
+       (fold_widened_comparison, fold_sign_changed_comparison): New functions.
+       (fold): Use them.
+       * tree-ssa-loop-niter.c (upper_bound_in_type, lower_bound_in_type):
+       Moved ...
+       * tree.c (upper_bound_in_type, lower_bound_in_type): Here.
+       * tree.h (upper_bound_in_type, lower_bound_in_type): Declare.
+
 2004-11-14  Eric Botcazou <ebotcazou@libertysurf.fr>
 
        * doc/rtl.texi (SUBREG): Adjust BYTENUM value.
index b8ccfa1d20708156385bed0cf755e49a5a052d2d..0d2e407692678c2d27c5afe78618347ff209cfa4 100644 (file)
@@ -1267,7 +1267,15 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
          else if (TREE_CODE (t2) == NEGATE_EXPR)
            return build2 (MINUS_EXPR, type, fold_convert (type, t1),
                           fold_convert (type, TREE_OPERAND (t2, 0)));
+         else if (integer_zerop (t2))
+           return fold_convert (type, t1);
        }
+      else if (code == MINUS_EXPR)
+       {
+         if (integer_zerop (t2))
+           return fold_convert (type, t1);
+       }
+
       return build2 (code, type, fold_convert (type, t1),
                     fold_convert (type, t2));
     }
@@ -5972,6 +5980,127 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
   return 0;
 }
 
+/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where
+   ARG0 is extended to a wider type.  */
+
+static tree
+fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
+{
+  tree arg0_unw = get_unwidened (arg0, NULL_TREE);
+  tree arg1_unw;
+  tree shorter_type, outer_type;
+  tree min, max;
+  bool above, below;
+
+  if (arg0_unw == arg0)
+    return NULL_TREE;
+  shorter_type = TREE_TYPE (arg0_unw);
+  
+  arg1_unw = get_unwidened (arg1, shorter_type);
+  if (!arg1_unw)
+    return NULL_TREE;
+
+  /* If possible, express the comparison in the shorter mode.  */
+  if ((code == EQ_EXPR || code == NE_EXPR
+       || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
+      && (TREE_TYPE (arg1_unw) == shorter_type
+         || (TREE_CODE (arg1_unw) == INTEGER_CST
+             && int_fits_type_p (arg1_unw, shorter_type))))
+    return fold (build (code, type, arg0_unw,
+                       fold_convert (shorter_type, arg1_unw)));
+
+  if (TREE_CODE (arg1_unw) != INTEGER_CST)
+    return NULL_TREE;
+
+  /* If we are comparing with the integer that does not fit into the range
+     of the shorter type, the result is known.  */
+  outer_type = TREE_TYPE (arg1_unw);
+  min = lower_bound_in_type (outer_type, shorter_type);
+  max = upper_bound_in_type (outer_type, shorter_type);
+
+  above = integer_nonzerop (fold_relational_const (LT_EXPR, type,
+                                                  max, arg1_unw));
+  below = integer_nonzerop (fold_relational_const (LT_EXPR, type,
+                                                  arg1_unw, min));
+
+  switch (code)
+    {
+    case EQ_EXPR:
+      if (above || below)
+       return constant_boolean_node (false, type);
+      break;
+
+    case NE_EXPR:
+      if (above || below)
+       return constant_boolean_node (true, type);
+      break;
+
+    case LT_EXPR:
+    case LE_EXPR:
+      if (above)
+       return constant_boolean_node (true, type);
+      else if (below)
+       return constant_boolean_node (false, type);;
+
+    case GT_EXPR:
+    case GE_EXPR:
+      if (above)
+       return constant_boolean_node (false, type);
+      else if (below)
+       return constant_boolean_node (true, type);;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where for
+   ARG0 just the signedness is changed.  */
+
+static tree
+fold_sign_changed_comparison (enum tree_code code, tree type,
+                             tree arg0, tree arg1)
+{
+  tree arg0_inner, tmp;
+  tree inner_type, outer_type;
+
+  if (TREE_CODE (arg0) != NOP_EXPR)
+    return NULL_TREE;
+
+  outer_type = TREE_TYPE (arg0);
+  arg0_inner = TREE_OPERAND (arg0, 0);
+  inner_type = TREE_TYPE (arg0_inner);
+
+  if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+    return NULL_TREE;
+
+  if (TREE_CODE (arg1) != INTEGER_CST
+      && !(TREE_CODE (arg1) == NOP_EXPR
+          && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type))
+    return NULL_TREE;
+
+  if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+      && code != NE_EXPR
+      && code != EQ_EXPR)
+    return NULL_TREE;
+
+  if (TREE_CODE (arg1) == INTEGER_CST)
+    {
+      tmp = build_int_cst_wide (inner_type,
+                               TREE_INT_CST_LOW (arg1),
+                               TREE_INT_CST_HIGH (arg1));
+      arg1 = force_fit_type (tmp, 0,
+                            TREE_OVERFLOW (arg1),
+                            TREE_CONSTANT_OVERFLOW (arg1));
+    }
+  else
+    arg1 = fold_convert (inner_type, arg1);
+
+  return fold (build (code, type, arg0_inner, arg1));
+}
+
 /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
    step of the array.  TYPE is the type of the expression.  ADDR is the address.
    MULT is the multiplicative expression.  If the function succeeds, the new
@@ -8392,22 +8521,21 @@ fold (tree expr)
        return fold (build2 (code, type,
                             TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
 
-      /* If we are widening one operand of an integer comparison,
-        see if the other operand is similarly being widened.  Perhaps we
-        can do the comparison in the narrower type.  */
       else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
-              && TREE_CODE (arg0) == NOP_EXPR
-              && (tem = get_unwidened (arg0, NULL_TREE)) != arg0
-              && (code == EQ_EXPR || code == NE_EXPR
-                  || TYPE_UNSIGNED (TREE_TYPE (arg0))
-                     == TYPE_UNSIGNED (TREE_TYPE (tem)))
-              && (t1 = get_unwidened (arg1, TREE_TYPE (tem))) != 0
-              && (TREE_TYPE (t1) == TREE_TYPE (tem)
-                  || (TREE_CODE (t1) == INTEGER_CST
-                      && TREE_CODE (TREE_TYPE (tem)) == INTEGER_TYPE
-                      && int_fits_type_p (t1, TREE_TYPE (tem)))))
-       return fold (build2 (code, type, tem,
-                            fold_convert (TREE_TYPE (tem), t1)));
+              && TREE_CODE (arg0) == NOP_EXPR)
+       {
+         /* If we are widening one operand of an integer comparison,
+            see if the other operand is similarly being widened.  Perhaps we
+            can do the comparison in the narrower type.  */
+         tem = fold_widened_comparison (code, type, arg0, arg1);
+         if (tem)
+           return tem;
+
+         /* Or if we are changing signedness.  */
+         tem = fold_sign_changed_comparison (code, type, arg0, arg1);
+         if (tem)
+           return tem;
+       }
 
       /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
         constant, we can simplify it.  */
index c21b4e1ec1469ec2c24bc47132a25df8dd7c1d58..3fda6f68c2fd9537e0fb0b31471a971d2c7c1839 100644 (file)
@@ -1,3 +1,7 @@
+2004-11-14  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       * gcc.c-torture/execute/20041114-1.c: New test.
+
 2004-11-14  Joseph S. Myers  <joseph@codesourcery.com>
 
        * gcc.dg/c99-flex-array-5.c, gcc.dg/c99-fordecl-3.c,
diff --git a/gcc/testsuite/gcc.c-torture/execute/20041114-1.c b/gcc/testsuite/gcc.c-torture/execute/20041114-1.c
new file mode 100644 (file)
index 0000000..4f82f8a
--- /dev/null
@@ -0,0 +1,35 @@
+/* Verify that
+   
+   var <= 0 || ((long unsigned) (unsigned) (var - 1) < MAX_UNSIGNED_INT)
+
+   gets folded to 1.  */
+
+#include <limits.h>
+
+void abort (void);
+void link_failure (void);
+
+volatile int v;
+
+void 
+foo (int var)
+{
+  if (!(var <= 0
+        || ((long unsigned) (unsigned) (var - 1) < UINT_MAX)))
+    link_failure ();
+}
+
+int
+main (int argc, char **argv)
+{
+  foo (v);
+  return 0;
+}
+
+#ifndef __OPTIMIZE__
+void
+link_failure (void)
+{
+  abort ();
+}
+#endif
index 6352ba0345edce791b0df6494af33ead026cd2fc..3d4d4c0dec4544f5f702bfc3bb334ab6867d74cc 100644 (file)
@@ -1103,78 +1103,6 @@ compare_trees (tree a, tree b)
   return 2;
 }
 
-/* Returns the largest value obtainable by casting something in INNER type to
-   OUTER type.  */
-
-static tree
-upper_bound_in_type (tree outer, tree inner)
-{
-  unsigned HOST_WIDE_INT lo, hi;
-  unsigned bits = TYPE_PRECISION (inner);
-
-  if (TYPE_UNSIGNED (outer) || TYPE_UNSIGNED (inner))
-    {
-      /* Zero extending in these cases.  */
-      if (bits <= HOST_BITS_PER_WIDE_INT)
-       {
-         hi = 0;
-         lo = (~(unsigned HOST_WIDE_INT) 0)
-                 >> (HOST_BITS_PER_WIDE_INT - bits);
-       }
-      else
-       {
-         hi = (~(unsigned HOST_WIDE_INT) 0)
-                 >> (2 * HOST_BITS_PER_WIDE_INT - bits);
-         lo = ~(unsigned HOST_WIDE_INT) 0;
-       }
-    }
-  else
-    {
-      /* Sign extending in these cases.  */
-      if (bits <= HOST_BITS_PER_WIDE_INT)
-       {
-         hi = 0;
-         lo = (~(unsigned HOST_WIDE_INT) 0)
-                 >> (HOST_BITS_PER_WIDE_INT - bits) >> 1;
-       }
-      else
-       {
-         hi = (~(unsigned HOST_WIDE_INT) 0)
-                 >> (2 * HOST_BITS_PER_WIDE_INT - bits) >> 1;
-         lo = ~(unsigned HOST_WIDE_INT) 0;
-       }
-    }
-
-  return fold_convert (outer,
-                      build_int_cst_wide (inner, lo, hi));
-}
-
-/* Returns the smallest value obtainable by casting something in INNER type to
-   OUTER type.  */
-
-static tree
-lower_bound_in_type (tree outer, tree inner)
-{
-  unsigned HOST_WIDE_INT lo, hi;
-  unsigned bits = TYPE_PRECISION (inner);
-
-  if (TYPE_UNSIGNED (outer) || TYPE_UNSIGNED (inner))
-    lo = hi = 0;
-  else if (bits <= HOST_BITS_PER_WIDE_INT)
-    {
-      hi = ~(unsigned HOST_WIDE_INT) 0;
-      lo = (~(unsigned HOST_WIDE_INT) 0) << (bits - 1);
-    }
-  else
-    {
-      hi = (~(unsigned HOST_WIDE_INT) 0) << (bits - HOST_BITS_PER_WIDE_INT - 1);
-      lo = 0;
-    }
-
-  return fold_convert (outer,
-                      build_int_cst_wide (inner, lo, hi));
-}
-
 /* Returns true if statement S1 dominates statement S2.  */
 
 static bool
index a05dab73f73b1dd29c62d4344c131bfabe5a5649..654ce785857f7797d6cdd8bad38c6d7a5f4e7851 100644 (file)
@@ -6074,4 +6074,76 @@ get_case_label (tree t)
   return CASE_LEADER_OR_LABEL (t);
 }
 
+/* Returns the largest value obtainable by casting something in INNER type to
+   OUTER type.  */
+
+tree
+upper_bound_in_type (tree outer, tree inner)
+{
+  unsigned HOST_WIDE_INT lo, hi;
+  unsigned bits = TYPE_PRECISION (inner);
+
+  if (TYPE_UNSIGNED (outer) || TYPE_UNSIGNED (inner))
+    {
+      /* Zero extending in these cases.  */
+      if (bits <= HOST_BITS_PER_WIDE_INT)
+       {
+         hi = 0;
+         lo = (~(unsigned HOST_WIDE_INT) 0)
+                 >> (HOST_BITS_PER_WIDE_INT - bits);
+       }
+      else
+       {
+         hi = (~(unsigned HOST_WIDE_INT) 0)
+                 >> (2 * HOST_BITS_PER_WIDE_INT - bits);
+         lo = ~(unsigned HOST_WIDE_INT) 0;
+       }
+    }
+  else
+    {
+      /* Sign extending in these cases.  */
+      if (bits <= HOST_BITS_PER_WIDE_INT)
+       {
+         hi = 0;
+         lo = (~(unsigned HOST_WIDE_INT) 0)
+                 >> (HOST_BITS_PER_WIDE_INT - bits) >> 1;
+       }
+      else
+       {
+         hi = (~(unsigned HOST_WIDE_INT) 0)
+                 >> (2 * HOST_BITS_PER_WIDE_INT - bits) >> 1;
+         lo = ~(unsigned HOST_WIDE_INT) 0;
+       }
+    }
+
+  return fold_convert (outer,
+                      build_int_cst_wide (inner, lo, hi));
+}
+
+/* Returns the smallest value obtainable by casting something in INNER type to
+   OUTER type.  */
+
+tree
+lower_bound_in_type (tree outer, tree inner)
+{
+  unsigned HOST_WIDE_INT lo, hi;
+  unsigned bits = TYPE_PRECISION (inner);
+
+  if (TYPE_UNSIGNED (outer) || TYPE_UNSIGNED (inner))
+    lo = hi = 0;
+  else if (bits <= HOST_BITS_PER_WIDE_INT)
+    {
+      hi = ~(unsigned HOST_WIDE_INT) 0;
+      lo = (~(unsigned HOST_WIDE_INT) 0) << (bits - 1);
+    }
+  else
+    {
+      hi = (~(unsigned HOST_WIDE_INT) 0) << (bits - HOST_BITS_PER_WIDE_INT - 1);
+      lo = 0;
+    }
+
+  return fold_convert (outer,
+                      build_int_cst_wide (inner, lo, hi));
+}
+
 #include "gt-tree.h"
index 4e5a6eaa45abe897a0b1e123f0c90149746c0ba2..a8670d9298932ef7d2ac2327a77ffd2d0b368133 100644 (file)
@@ -3464,7 +3464,8 @@ extern int type_num_arguments (tree);
 extern bool associative_tree_code (enum tree_code);
 extern bool commutative_tree_code (enum tree_code);
 extern tree get_case_label (tree);
-
+extern tree upper_bound_in_type (tree, tree);
+extern tree lower_bound_in_type (tree, tree);
 \f
 /* In stmt.c */