diff options
author | rakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-11-15 00:18:37 +0000 |
---|---|---|
committer | rakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-11-15 00:18:37 +0000 |
commit | faab57e3cef4a6034b2336ac1a015b11733a370d (patch) | |
tree | 8a20893a5c5c0b8de8fe5ddf927281ae604e7f1d | |
parent | 2eaea01e7a391c5d44b15592423011f1fd2b59e0 (diff) | |
download | gcc-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/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/fold-const.c | 158 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20041114-1.c | 35 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-niter.c | 72 | ||||
-rw-r--r-- | gcc/tree.c | 72 | ||||
-rw-r--r-- | gcc/tree.h | 3 |
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 */ |