summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2004-11-15 00:18:37 +0000
committerrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>2004-11-15 00:18:37 +0000
commitfaab57e3cef4a6034b2336ac1a015b11733a370d (patch)
tree8a20893a5c5c0b8de8fe5ddf927281ae604e7f1d
parent2eaea01e7a391c5d44b15592423011f1fd2b59e0 (diff)
downloadgcc-faab57e3cef4a6034b2336ac1a015b11733a370d.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@90646 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/fold-const.c158
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20041114-1.c35
-rw-r--r--gcc/tree-ssa-loop-niter.c72
-rw-r--r--gcc/tree.c72
-rw-r--r--gcc/tree.h3
7 files changed, 267 insertions, 88 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 84cd2b0d38d..c26b57c832d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index b8ccfa1d207..0d2e4076926 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -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. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c21b4e1ec14..3fda6f68c2f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..4f82f8aa229
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20041114-1.c
@@ -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
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 6352ba0345e..3d4d4c0dec4 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -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
diff --git a/gcc/tree.c b/gcc/tree.c
index a05dab73f73..654ce785857 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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"
diff --git a/gcc/tree.h b/gcc/tree.h
index 4e5a6eaa45a..a8670d92989 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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);
/* In stmt.c */