This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] Reorganize relational operator folding in fold_binary
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 24 Feb 2006 11:54:26 -0700 (MST)
- Subject: [Committed] Reorganize relational operator folding in fold_binary
The following patch is a reorganization of the way that relational,
i.e. comparison, operators are handled in fold-const.c. Previously,
all six relational operators (EQ_EXPR, NE_EXPR, LT_EXPR, LE_EXPR,
GE_EXPR and GT_EXPR) were all handled in a single hunk in fold_binary's
switch statement. The patch below refactors this code such that
equality/inequality operators (EQ_EXPR and NE_EXPR) are distinguished
from ordering operators (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR).
All of the transformations common to both (which are relatively rare)
are factored into a new subroutine, fold_comparison, which is invoked
for both equality and relational operators.
It turns out that the repeated need to test whether "code" is either
EQ_EXPR or NE_EXPR in the original source, means that this restructuring
actually decreases the number of lines in fold-const.c. Modulo the
new function call, it should also speed up fold_binary, as we now
better restrict the possible transformations based on the incoming
tree code. I've several pending patches to address middle-end PRs
that introduce new optimizations, but which consistently only apply
to equality/inequality operators.
There should be no functional differences with the change.
However reordering these optimizations did expose two latent bugs
in fold_div_compare (addressed below) as LT_EXPR and GE_EXPR against
integer constants didn't previously reach the problematic code.
Hopefully, there are no other latent problems, but let me know.
The following patch was tested on x86_64-unknown-linux-gnu with a
full "make bootstrap", all default languages, and regression tested
with a top-level "make -k check" with no new failures.
Committed to mainline as revision 111423.
2006-02-24 Roger Sayle <roger@eyesopen.com>
* fold-const.c (fold_comparison): New subroutine of fold_binary
containing transformations common to both the equality and
ordering relational operators, factored out of fold_binary.
(fold_binary): Separate out the equality operators (EQ_EXPR
and NE_EXPR) from the ordering operators (LT_EXPR, GT_EXPR,
LE_EXPR and GE_EXPR), calling fold_comparison to perform the
transformations common to both.
(fold_div_compare): Fix latent bugs in the previously unreachable
LT_EXPR and GE_EXPR cases.
Index: fold-const.c
===================================================================
*** fold-const.c (revision 111392)
--- fold-const.c (working copy)
*************** fold_div_compare (enum tree_code code, t
*** 6114,6120 ****
case LT_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_zero_node, arg00);
return fold_build2 (LT_EXPR, type, arg00, lo);
case LE_EXPR:
--- 6114,6120 ----
case LT_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_one_node, arg00);
return fold_build2 (LT_EXPR, type, arg00, lo);
case LE_EXPR:
*************** fold_div_compare (enum tree_code code, t
*** 6129,6135 ****
case GE_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_one_node, arg00);
return fold_build2 (GE_EXPR, type, arg00, lo);
default:
--- 6129,6135 ----
case GE_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_zero_node, arg00);
return fold_build2 (GE_EXPR, type, arg00, lo);
default:
*************** fold_minmax (enum tree_code code, tree t
*** 7223,7228 ****
--- 7223,7668 ----
return NULL_TREE;
}
+ /* 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
+ (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR). Callers other than
+ fold_binary should call fold_binary. Fold a comparison with
+ tree code CODE and type TYPE with operands OP0 and OP1. Return
+ the folded comparison or NULL_TREE. */
+
+ static tree
+ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
+ {
+ tree arg0, arg1, tem;
+
+ arg0 = op0;
+ arg1 = op1;
+
+ STRIP_SIGN_NOPS (arg0);
+ STRIP_SIGN_NOPS (arg1);
+
+ tem = fold_relational_const (code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+
+ /* If one arg is a real or integer constant, put it last. */
+ if (tree_swap_operands_p (arg0, arg1, true))
+ return fold_build2 (swap_tree_comparison (code), type, op1, op0);
+
+ /* If this is a comparison of two exprs that look like an
+ ARRAY_REF of the same object, then we can fold this to a
+ comparison of the two offsets. */
+ {
+ tree base0, offset0, base1, offset1;
+
+ if (extract_array_ref (arg0, &base0, &offset0)
+ && extract_array_ref (arg1, &base1, &offset1)
+ && operand_equal_p (base0, base1, 0))
+ {
+ /* Handle no offsets on both sides specially. */
+ if (offset0 == NULL_TREE && offset1 == NULL_TREE)
+ return fold_build2 (code, type, integer_zero_node,
+ integer_zero_node);
+
+ if (!offset0 || !offset1
+ || TREE_TYPE (offset0) == TREE_TYPE (offset1))
+ {
+ if (offset0 == NULL_TREE)
+ offset0 = build_int_cst (TREE_TYPE (offset1), 0);
+ if (offset1 == NULL_TREE)
+ offset1 = build_int_cst (TREE_TYPE (offset0), 0);
+ return fold_build2 (code, type, offset0, offset1);
+ }
+ }
+ }
+
+ /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1. */
+ if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+ && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+ && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+ && !TYPE_UNSIGNED (TREE_TYPE (arg1))
+ && !(flag_wrapv || flag_trapv))
+ && (TREE_CODE (arg1) == INTEGER_CST
+ && !TREE_OVERFLOW (arg1)))
+ {
+ tree const1 = TREE_OPERAND (arg0, 1);
+ tree const2 = arg1;
+ tree variable = TREE_OPERAND (arg0, 0);
+ tree lhs;
+ int lhs_add;
+ lhs_add = TREE_CODE (arg0) != PLUS_EXPR;
+
+ lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR,
+ TREE_TYPE (arg1), const2, const1);
+ if (TREE_CODE (lhs) == TREE_CODE (arg1)
+ && (TREE_CODE (lhs) != INTEGER_CST
+ || !TREE_OVERFLOW (lhs)))
+ return fold_build2 (code, type, variable, lhs);
+ }
+
+ if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
+ {
+ tree targ0 = strip_float_extensions (arg0);
+ tree targ1 = strip_float_extensions (arg1);
+ tree newtype = TREE_TYPE (targ0);
+
+ if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+ newtype = TREE_TYPE (targ1);
+
+ /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
+ if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+ return fold_build2 (code, type, fold_convert (newtype, targ0),
+ fold_convert (newtype, targ1));
+
+ /* (-a) CMP (-b) -> b CMP a */
+ if (TREE_CODE (arg0) == NEGATE_EXPR
+ && TREE_CODE (arg1) == NEGATE_EXPR)
+ return fold_build2 (code, type, TREE_OPERAND (arg1, 0),
+ TREE_OPERAND (arg0, 0));
+
+ if (TREE_CODE (arg1) == REAL_CST)
+ {
+ REAL_VALUE_TYPE cst;
+ cst = TREE_REAL_CST (arg1);
+
+ /* (-a) CMP CST -> a swap(CMP) (-CST) */
+ if (TREE_CODE (arg0) == NEGATE_EXPR)
+ return fold_build2 (swap_tree_comparison (code), type,
+ TREE_OPERAND (arg0, 0),
+ build_real (TREE_TYPE (arg1),
+ REAL_VALUE_NEGATE (cst)));
+
+ /* IEEE doesn't distinguish +0 and -0 in comparisons. */
+ /* a CMP (-0) -> a CMP 0 */
+ if (REAL_VALUE_MINUS_ZERO (cst))
+ return fold_build2 (code, type, arg0,
+ build_real (TREE_TYPE (arg1), dconst0));
+
+ /* x != NaN is always true, other ops are always false. */
+ if (REAL_VALUE_ISNAN (cst)
+ && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
+ {
+ tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+ return omit_one_operand (type, tem, arg0);
+ }
+
+ /* Fold comparisons against infinity. */
+ if (REAL_VALUE_ISINF (cst))
+ {
+ tem = fold_inf_compare (code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+ }
+
+ /* If this is a comparison of a real constant with a PLUS_EXPR
+ or a MINUS_EXPR of a real constant, we can convert it into a
+ comparison with a revised real constant as long as no overflow
+ occurs when unsafe_math_optimizations are enabled. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg1) == REAL_CST
+ && (TREE_CODE (arg0) == PLUS_EXPR
+ || TREE_CODE (arg0) == MINUS_EXPR)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+ && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
+ ? MINUS_EXPR : PLUS_EXPR,
+ arg1, TREE_OPERAND (arg0, 1), 0))
+ && ! TREE_CONSTANT_OVERFLOW (tem))
+ return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
+
+ /* Likewise, we can simplify a comparison of a real constant with
+ a MINUS_EXPR whose first operand is also a real constant, i.e.
+ (c1 - x) < c2 becomes x > c1-c2. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg1) == REAL_CST
+ && TREE_CODE (arg0) == MINUS_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
+ && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
+ arg1, 0))
+ && ! TREE_CONSTANT_OVERFLOW (tem))
+ return fold_build2 (swap_tree_comparison (code), type,
+ TREE_OPERAND (arg0, 1), tem);
+
+ /* Fold comparisons against built-in math functions. */
+ if (TREE_CODE (arg1) == REAL_CST
+ && flag_unsafe_math_optimizations
+ && ! flag_errno_math)
+ {
+ enum built_in_function fcode = builtin_mathfn_code (arg0);
+
+ if (fcode != END_BUILTINS)
+ {
+ tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+ }
+ }
+
+ /* Convert foo++ == CONST into ++foo == CONST + INCR. */
+ if (TREE_CONSTANT (arg1)
+ && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
+ || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
+ /* This optimization is invalid for ordered comparisons
+ if CONST+INCR overflows or if foo+incr might overflow.
+ This optimization is invalid for floating point due to rounding.
+ For pointer types we assume overflow doesn't happen. */
+ && (POINTER_TYPE_P (TREE_TYPE (arg0))
+ || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && (code == EQ_EXPR || code == NE_EXPR))))
+ {
+ tree varop, newconst;
+
+ if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
+ {
+ newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
+ arg1, TREE_OPERAND (arg0, 1));
+ varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1));
+ }
+ else
+ {
+ newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
+ arg1, TREE_OPERAND (arg0, 1));
+ varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1));
+ }
+
+
+ /* If VAROP is a reference to a bitfield, we must mask
+ the constant by the width of the field. */
+ if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
+ && host_integerp (DECL_SIZE (TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)), 1))
+ {
+ tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
+ HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
+ tree folded_compare, shift;
+
+ /* First check whether the comparison would come out
+ always the same. If we don't do that we would
+ change the meaning with the masking. */
+ folded_compare = fold_build2 (code, type,
+ TREE_OPERAND (varop, 0), arg1);
+ if (TREE_CODE (folded_compare) == INTEGER_CST)
+ return omit_one_operand (type, folded_compare, varop);
+
+ shift = build_int_cst (NULL_TREE,
+ TYPE_PRECISION (TREE_TYPE (varop)) - size);
+ shift = fold_convert (TREE_TYPE (varop), shift);
+ newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+ newconst, shift);
+ newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+ newconst, shift);
+ }
+
+ return fold_build2 (code, type, varop, newconst);
+ }
+
+ if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
+ && (TREE_CODE (arg0) == NOP_EXPR
+ || TREE_CODE (arg0) == CONVERT_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. */
+ if (TREE_CODE (arg1) == INTEGER_CST
+ && (TREE_CODE (arg0) == MIN_EXPR
+ || TREE_CODE (arg0) == MAX_EXPR)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+ {
+ tem = optimize_minmax_comparison (code, type, op0, op1);
+ if (tem)
+ return tem;
+ }
+
+ /* Simplify comparison of something with itself. (For IEEE
+ floating-point, we can only do some of these simplifications.) */
+ if (operand_equal_p (arg0, arg1, 0))
+ {
+ switch (code)
+ {
+ case EQ_EXPR:
+ if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+ || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return constant_boolean_node (1, type);
+ break;
+
+ case GE_EXPR:
+ case LE_EXPR:
+ if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+ || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return constant_boolean_node (1, type);
+ return fold_build2 (EQ_EXPR, type, arg0, arg1);
+
+ case NE_EXPR:
+ /* For NE, we can only do this simplification if integer
+ or we don't honor IEEE floating point NaNs. */
+ if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+ && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ break;
+ /* ... fall through ... */
+ case GT_EXPR:
+ case LT_EXPR:
+ return constant_boolean_node (0, type);
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ /* If we are comparing an expression that just has comparisons
+ of two integer values, arithmetic expressions of those comparisons,
+ and constants, we can simplify it. There are only three cases
+ to check: the two values can either be equal, the first can be
+ greater, or the second can be greater. Fold the expression for
+ those three values. Since each value must be 0 or 1, we have
+ eight possibilities, each of which corresponds to the constant 0
+ or 1 or one of the six possible comparisons.
+
+ This handles common cases like (a > b) == 0 but also handles
+ expressions like ((x > y) - (y > x)) > 0, which supposedly
+ occur in macroized code. */
+
+ if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST)
+ {
+ tree cval1 = 0, cval2 = 0;
+ int save_p = 0;
+
+ if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p)
+ /* Don't handle degenerate cases here; they should already
+ have been handled anyway. */
+ && cval1 != 0 && cval2 != 0
+ && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
+ && TREE_TYPE (cval1) == TREE_TYPE (cval2)
+ && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval2))
+ && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
+ TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
+ {
+ tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1));
+ tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1));
+
+ /* We can't just pass T to eval_subst in case cval1 or cval2
+ was the same as ARG1. */
+
+ tree high_result
+ = fold_build2 (code, type,
+ eval_subst (arg0, cval1, maxval,
+ cval2, minval),
+ arg1);
+ tree equal_result
+ = fold_build2 (code, type,
+ eval_subst (arg0, cval1, maxval,
+ cval2, maxval),
+ arg1);
+ tree low_result
+ = fold_build2 (code, type,
+ eval_subst (arg0, cval1, minval,
+ cval2, maxval),
+ arg1);
+
+ /* All three of these results should be 0 or 1. Confirm they are.
+ Then use those values to select the proper code to use. */
+
+ if (TREE_CODE (high_result) == INTEGER_CST
+ && TREE_CODE (equal_result) == INTEGER_CST
+ && TREE_CODE (low_result) == INTEGER_CST)
+ {
+ /* Make a 3-bit mask with the high-order bit being the
+ value for `>', the next for '=', and the low for '<'. */
+ switch ((integer_onep (high_result) * 4)
+ + (integer_onep (equal_result) * 2)
+ + integer_onep (low_result))
+ {
+ case 0:
+ /* Always false. */
+ return omit_one_operand (type, integer_zero_node, arg0);
+ case 1:
+ code = LT_EXPR;
+ break;
+ case 2:
+ code = EQ_EXPR;
+ break;
+ case 3:
+ code = LE_EXPR;
+ break;
+ case 4:
+ code = GT_EXPR;
+ break;
+ case 5:
+ code = NE_EXPR;
+ break;
+ case 6:
+ code = GE_EXPR;
+ break;
+ case 7:
+ /* Always true. */
+ return omit_one_operand (type, integer_one_node, arg0);
+ }
+
+ if (save_p)
+ return save_expr (build2 (code, type, cval1, cval2));
+ return fold_build2 (code, type, cval1, cval2);
+ }
+ }
+ }
+
+ /* Fold a comparison of the address of COMPONENT_REFs with the same
+ type and component to a comparison of the address of the base
+ object. In short, &x->a OP &y->a to x OP y and
+ &x->a OP &y.a to x OP &y */
+ if (TREE_CODE (arg0) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
+ && TREE_CODE (arg1) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
+ {
+ tree cref0 = TREE_OPERAND (arg0, 0);
+ tree cref1 = TREE_OPERAND (arg1, 0);
+ if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
+ {
+ tree op0 = TREE_OPERAND (cref0, 0);
+ tree op1 = TREE_OPERAND (cref1, 0);
+ return fold_build2 (code, type,
+ build_fold_addr_expr (op0),
+ build_fold_addr_expr (op1));
+ }
+ }
+
+ /* We can fold X/C1 op C2 where C1 and C2 are integer constants
+ into a single range test. */
+ if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
+ || TREE_CODE (arg0) == EXACT_DIV_EXPR)
+ && TREE_CODE (arg1) == INTEGER_CST
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+ && !integer_zerop (TREE_OPERAND (arg0, 1))
+ && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+ && !TREE_OVERFLOW (arg1))
+ {
+ tem = fold_div_compare (code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+
+ return NULL_TREE;
+ }
+
/* Fold a binary expression of code CODE and type TYPE with operands
OP0 and OP1. Return the folded expression if folding is
successful. Otherwise, return NULL_TREE. */
*************** fold_minmax (enum tree_code code, tree t
*** 7230,7239 ****
tree
fold_binary (enum tree_code code, tree type, tree op0, tree op1)
{
- tree t1 = NULL_TREE;
- tree tem;
- tree arg0 = NULL_TREE, arg1 = NULL_TREE;
enum tree_code_class kind = TREE_CODE_CLASS (code);
gcc_assert (IS_EXPR_CODE_CLASS (kind)
&& TREE_CODE_LENGTH (code) == 2
--- 7670,7678 ----
tree
fold_binary (enum tree_code code, tree type, tree op0, tree op1)
{
enum tree_code_class kind = TREE_CODE_CLASS (code);
+ tree arg0, arg1, tem;
+ tree t1 = NULL_TREE;
gcc_assert (IS_EXPR_CODE_CLASS (kind)
&& TREE_CODE_LENGTH (code) == 2
*************** fold_binary (enum tree_code code, tree t
*** 9055,9080 ****
case EQ_EXPR:
case NE_EXPR:
! case LT_EXPR:
! case GT_EXPR:
! case LE_EXPR:
! case GE_EXPR:
! /* If one arg is a real or integer constant, put it last. */
! if (tree_swap_operands_p (arg0, arg1, true))
! return fold_build2 (swap_tree_comparison (code), type, op1, op0);
- /* ~a != C becomes a != ~C where C is a constant. Likewise for ==. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR && TREE_CODE (arg1) == INTEGER_CST
- && (code == NE_EXPR || code == EQ_EXPR))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
- fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1),
- arg1));
-
/* bool_var != 0 becomes bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
&& code == NE_EXPR)
return non_lvalue (fold_convert (type, arg0));
!
/* bool_var == 1 becomes bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == EQ_EXPR)
--- 9494,9508 ----
case EQ_EXPR:
case NE_EXPR:
! tem = fold_comparison (code, type, op0, op1);
! if (tem != NULL_TREE)
! return tem;
/* bool_var != 0 becomes bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
&& code == NE_EXPR)
return non_lvalue (fold_convert (type, arg0));
!
/* bool_var == 1 becomes bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == EQ_EXPR)
*************** fold_binary (enum tree_code code, tree t
*** 9090,9099 ****
&& code == EQ_EXPR)
return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
/* If this is an equality comparison of the address of a non-weak
object against zero, then we know the result. */
! if ((code == EQ_EXPR || code == NE_EXPR)
! && TREE_CODE (arg0) == ADDR_EXPR
&& VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
&& ! DECL_WEAK (TREE_OPERAND (arg0, 0))
&& integer_zerop (arg1))
--- 9518,9533 ----
&& code == EQ_EXPR)
return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
+ /* ~a != C becomes a != ~C where C is a constant. Likewise for ==. */
+ if (TREE_CODE (arg0) == BIT_NOT_EXPR
+ && TREE_CODE (arg1) == INTEGER_CST)
+ return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+ fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1),
+ arg1));
+
/* If this is an equality comparison of the address of a non-weak
object against zero, then we know the result. */
! if (TREE_CODE (arg0) == ADDR_EXPR
&& VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
&& ! DECL_WEAK (TREE_OPERAND (arg0, 0))
&& integer_zerop (arg1))
*************** fold_binary (enum tree_code code, tree t
*** 9102,9109 ****
/* If this is an equality comparison of the address of two non-weak,
unaliased symbols neither of which are extern (since we do not
have access to attributes for externs), then we know the result. */
! if ((code == EQ_EXPR || code == NE_EXPR)
! && TREE_CODE (arg0) == ADDR_EXPR
&& VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
&& ! DECL_WEAK (TREE_OPERAND (arg0, 0))
&& ! lookup_attribute ("alias",
--- 9536,9542 ----
/* If this is an equality comparison of the address of two non-weak,
unaliased symbols neither of which are extern (since we do not
have access to attributes for externs), then we know the result. */
! if (TREE_CODE (arg0) == ADDR_EXPR
&& VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
&& ! DECL_WEAK (TREE_OPERAND (arg0, 0))
&& ! lookup_attribute ("alias",
*************** fold_binary (enum tree_code code, tree t
*** 9133,9188 ****
type);
}
! /* If this is a comparison of two exprs that look like an
! ARRAY_REF of the same object, then we can fold this to a
! comparison of the two offsets. */
! if (TREE_CODE_CLASS (code) == tcc_comparison)
! {
! tree base0, offset0, base1, offset1;
!
! if (extract_array_ref (arg0, &base0, &offset0)
! && extract_array_ref (arg1, &base1, &offset1)
! && operand_equal_p (base0, base1, 0))
! {
! /* Handle no offsets on both sides specially. */
! if (offset0 == NULL_TREE
! && offset1 == NULL_TREE)
! return fold_build2 (code, type, integer_zero_node,
! integer_zero_node);
! if (!offset0 || !offset1
! || TREE_TYPE (offset0) == TREE_TYPE (offset1))
! {
! if (offset0 == NULL_TREE)
! offset0 = build_int_cst (TREE_TYPE (offset1), 0);
! if (offset1 == NULL_TREE)
! offset1 = build_int_cst (TREE_TYPE (offset0), 0);
! return fold_build2 (code, type, offset0, offset1);
! }
! }
! }
! /* Transform comparisons of the form X +- C CMP X. */
! if ((code != EQ_EXPR && code != NE_EXPR)
! && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
! && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
! && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
! && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
! || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && !TYPE_UNSIGNED (TREE_TYPE (arg1))
! && !(flag_wrapv || flag_trapv))))
{
tree arg01 = TREE_OPERAND (arg0, 1);
! enum tree_code code0 = TREE_CODE (arg0);
! int is_positive;
! if (TREE_CODE (arg01) == REAL_CST)
! is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
! else
! is_positive = tree_int_cst_sgn (arg01);
! /* (X - c) > X becomes false. */
! if (code == GT_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
return constant_boolean_node (0, type);
--- 9566,9808 ----
type);
}
! /* If this is an EQ or NE comparison of a constant with a PLUS_EXPR or
! a MINUS_EXPR of a constant, we can convert it into a comparison with
! a revised constant as long as no overflow occurs. */
! if (TREE_CODE (arg1) == INTEGER_CST
! && (TREE_CODE (arg0) == PLUS_EXPR
! || TREE_CODE (arg0) == MINUS_EXPR)
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
! ? MINUS_EXPR : PLUS_EXPR,
! arg1, TREE_OPERAND (arg0, 1), 0))
! && ! TREE_CONSTANT_OVERFLOW (tem))
! return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
! /* Similarly for a NEGATE_EXPR. */
! if (TREE_CODE (arg0) == NEGATE_EXPR
! && TREE_CODE (arg1) == INTEGER_CST
! && 0 != (tem = negate_expr (arg1))
! && TREE_CODE (tem) == INTEGER_CST
! && ! TREE_CONSTANT_OVERFLOW (tem))
! return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
! /* If we have X - Y == 0, we can convert that to X == Y and similarly
! for !=. Don't do this for ordered comparisons due to overflow. */
! if (TREE_CODE (arg0) == MINUS_EXPR
! && integer_zerop (arg1))
! return fold_build2 (code, type,
! TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
!
! /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */
! if (TREE_CODE (arg0) == ABS_EXPR
! && (integer_zerop (arg1) || real_zerop (arg1)))
! return fold_build2 (code, type, TREE_OPERAND (arg0, 0), arg1);
!
! /* If this is an EQ or NE comparison with zero and ARG0 is
! (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
! two operations, but the latter can be done in one less insn
! on machines that have only two-operand insns or on which a
! constant cannot be the first operand. */
! if (TREE_CODE (arg0) == BIT_AND_EXPR
! && integer_zerop (arg1))
{
+ tree arg00 = TREE_OPERAND (arg0, 0);
tree arg01 = TREE_OPERAND (arg0, 1);
! if (TREE_CODE (arg00) == LSHIFT_EXPR
! && integer_onep (TREE_OPERAND (arg00, 0)))
! return
! fold_build2 (code, type,
! build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
! build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
! arg01, TREE_OPERAND (arg00, 1)),
! fold_convert (TREE_TYPE (arg0),
! integer_one_node)),
! arg1);
! else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR
! && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0)))
! return
! fold_build2 (code, type,
! build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
! build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
! arg00, TREE_OPERAND (arg01, 1)),
! fold_convert (TREE_TYPE (arg0),
! integer_one_node)),
! arg1);
! }
! /* If this is an NE or EQ comparison of zero against the result of a
! signed MOD operation whose second operand is a power of 2, make
! the MOD operation unsigned since it is simpler and equivalent. */
! if (integer_zerop (arg1)
! && !TYPE_UNSIGNED (TREE_TYPE (arg0))
! && (TREE_CODE (arg0) == TRUNC_MOD_EXPR
! || TREE_CODE (arg0) == CEIL_MOD_EXPR
! || TREE_CODE (arg0) == FLOOR_MOD_EXPR
! || TREE_CODE (arg0) == ROUND_MOD_EXPR)
! && integer_pow2p (TREE_OPERAND (arg0, 1)))
! {
! tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
! tree newmod = fold_build2 (TREE_CODE (arg0), newtype,
! fold_convert (newtype,
! TREE_OPERAND (arg0, 0)),
! fold_convert (newtype,
! TREE_OPERAND (arg0, 1)));
! return fold_build2 (code, type, newmod,
! fold_convert (newtype, arg1));
! }
!
! /* If this is an NE comparison of zero with an AND of one, remove the
! comparison since the AND will give the correct value. */
! if (code == NE_EXPR
! && integer_zerop (arg1)
! && TREE_CODE (arg0) == BIT_AND_EXPR
! && integer_onep (TREE_OPERAND (arg0, 1)))
! return fold_convert (type, arg0);
!
! /* If we have (A & C) == C where C is a power of 2, convert this into
! (A & C) != 0. Similarly for NE_EXPR. */
! if (TREE_CODE (arg0) == BIT_AND_EXPR
! && integer_pow2p (TREE_OPERAND (arg0, 1))
! && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
! return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
! arg0, fold_convert (TREE_TYPE (arg0),
! integer_zero_node));
!
! /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
! bit, then fold the expression into A < 0 or A >= 0. */
! tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type);
! if (tem)
! return tem;
!
! /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
! Similarly for NE_EXPR. */
! if (TREE_CODE (arg0) == BIT_AND_EXPR
! && TREE_CODE (arg1) == INTEGER_CST
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
! {
! tree notc = fold_build1 (BIT_NOT_EXPR,
! TREE_TYPE (TREE_OPERAND (arg0, 1)),
! TREE_OPERAND (arg0, 1));
! tree dandnotc = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
! arg1, notc);
! tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
! if (integer_nonzerop (dandnotc))
! return omit_one_operand (type, rslt, arg0);
! }
!
! /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
! Similarly for NE_EXPR. */
! if (TREE_CODE (arg0) == BIT_IOR_EXPR
! && TREE_CODE (arg1) == INTEGER_CST
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
! {
! tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
! tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
! TREE_OPERAND (arg0, 1), notd);
! tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
! if (integer_nonzerop (candnotd))
! return omit_one_operand (type, rslt, arg0);
! }
!
! /* If this is a comparison of a field, we may be able to simplify it. */
! if (((TREE_CODE (arg0) == COMPONENT_REF
! && lang_hooks.can_use_bit_fields_p ())
! || TREE_CODE (arg0) == BIT_FIELD_REF)
! /* Handle the constant case even without -O
! to make sure the warnings are given. */
! && (optimize || TREE_CODE (arg1) == INTEGER_CST))
! {
! t1 = optimize_bit_field_compare (code, type, arg0, arg1);
! if (t1)
! return t1;
! }
!
! /* Optimize comparisons of strlen vs zero to a compare of the
! first character of the string vs zero. To wit,
! strlen(ptr) == 0 => *ptr == 0
! strlen(ptr) != 0 => *ptr != 0
! Other cases should reduce to one of these two (or a constant)
! due to the return value of strlen being unsigned. */
! if (TREE_CODE (arg0) == CALL_EXPR
! && integer_zerop (arg1))
! {
! tree fndecl = get_callee_fndecl (arg0);
! tree arglist;
!
! if (fndecl
! && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
! && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
! && (arglist = TREE_OPERAND (arg0, 1))
! && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
! && ! TREE_CHAIN (arglist))
! {
! tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
! return fold_build2 (code, type, iref,
! build_int_cst (TREE_TYPE (iref), 0));
! }
! }
!
! /* Fold (X >> C) != 0 into X < 0 if C is one less than the width
! of X. Similarly fold (X >> C) == 0 into X >= 0. */
! if (TREE_CODE (arg0) == RSHIFT_EXPR
! && integer_zerop (arg1)
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
! {
! tree arg00 = TREE_OPERAND (arg0, 0);
! tree arg01 = TREE_OPERAND (arg0, 1);
! tree itype = TREE_TYPE (arg00);
! if (TREE_INT_CST_HIGH (arg01) == 0
! && TREE_INT_CST_LOW (arg01)
! == (unsigned HOST_WIDE_INT) (TYPE_PRECISION (itype) - 1))
! {
! if (TYPE_UNSIGNED (itype))
! {
! itype = lang_hooks.types.signed_type (itype);
! arg00 = fold_convert (itype, arg00);
! }
! return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
! type, arg00, build_int_cst (itype, 0));
! }
! }
!
! if (integer_zerop (arg1)
! && tree_expr_nonzero_p (arg0))
! {
! tree res = constant_boolean_node (code==NE_EXPR, type);
! return omit_one_operand (type, res, arg0);
! }
! return NULL_TREE;
!
! case LT_EXPR:
! case GT_EXPR:
! case LE_EXPR:
! case GE_EXPR:
! tem = fold_comparison (code, type, op0, op1);
! if (tem != NULL_TREE)
! return tem;
!
! /* Transform comparisons of the form X +- C CMP X. */
! if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
! && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
! && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
! && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
! || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && !TYPE_UNSIGNED (TREE_TYPE (arg1))
! && !(flag_wrapv || flag_trapv))))
! {
! tree arg01 = TREE_OPERAND (arg0, 1);
! enum tree_code code0 = TREE_CODE (arg0);
! int is_positive;
!
! if (TREE_CODE (arg01) == REAL_CST)
! is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
! else
! is_positive = tree_int_cst_sgn (arg01);
!
! /* (X - c) > X becomes false. */
! if (code == GT_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
return constant_boolean_node (0, type);
*************** fold_binary (enum tree_code code, tree t
*** 9233,9426 ****
}
}
- /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1. */
- if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
- && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
- && !TYPE_UNSIGNED (TREE_TYPE (arg1))
- && !(flag_wrapv || flag_trapv))
- && (TREE_CODE (arg1) == INTEGER_CST
- && !TREE_OVERFLOW (arg1)))
- {
- tree const1 = TREE_OPERAND (arg0, 1);
- tree const2 = arg1;
- tree variable = TREE_OPERAND (arg0, 0);
- tree lhs;
- int lhs_add;
- lhs_add = TREE_CODE (arg0) != PLUS_EXPR;
-
- lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR,
- TREE_TYPE (arg1), const2, const1);
- if (TREE_CODE (lhs) == TREE_CODE (arg1)
- && (TREE_CODE (lhs) != INTEGER_CST
- || !TREE_OVERFLOW (lhs)))
- return fold_build2 (code, type, variable, lhs);
- }
-
- if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
- {
- tree targ0 = strip_float_extensions (arg0);
- tree targ1 = strip_float_extensions (arg1);
- tree newtype = TREE_TYPE (targ0);
-
- if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
- newtype = TREE_TYPE (targ1);
-
- /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
- if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
- return fold_build2 (code, type, fold_convert (newtype, targ0),
- fold_convert (newtype, targ1));
-
- /* (-a) CMP (-b) -> b CMP a */
- if (TREE_CODE (arg0) == NEGATE_EXPR
- && TREE_CODE (arg1) == NEGATE_EXPR)
- return fold_build2 (code, type, TREE_OPERAND (arg1, 0),
- TREE_OPERAND (arg0, 0));
-
- if (TREE_CODE (arg1) == REAL_CST)
- {
- REAL_VALUE_TYPE cst;
- cst = TREE_REAL_CST (arg1);
-
- /* (-a) CMP CST -> a swap(CMP) (-CST) */
- if (TREE_CODE (arg0) == NEGATE_EXPR)
- return
- fold_build2 (swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 0),
- build_real (TREE_TYPE (arg1),
- REAL_VALUE_NEGATE (cst)));
-
- /* IEEE doesn't distinguish +0 and -0 in comparisons. */
- /* a CMP (-0) -> a CMP 0 */
- if (REAL_VALUE_MINUS_ZERO (cst))
- return fold_build2 (code, type, arg0,
- build_real (TREE_TYPE (arg1), dconst0));
-
- /* x != NaN is always true, other ops are always false. */
- if (REAL_VALUE_ISNAN (cst)
- && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
- {
- tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
- return omit_one_operand (type, tem, arg0);
- }
-
- /* Fold comparisons against infinity. */
- if (REAL_VALUE_ISINF (cst))
- {
- tem = fold_inf_compare (code, type, arg0, arg1);
- if (tem != NULL_TREE)
- return tem;
- }
- }
-
- /* If this is a comparison of a real constant with a PLUS_EXPR
- or a MINUS_EXPR of a real constant, we can convert it into a
- comparison with a revised real constant as long as no overflow
- occurs when unsafe_math_optimizations are enabled. */
- if (flag_unsafe_math_optimizations
- && TREE_CODE (arg1) == REAL_CST
- && (TREE_CODE (arg0) == PLUS_EXPR
- || TREE_CODE (arg0) == MINUS_EXPR)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
- && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
- ? MINUS_EXPR : PLUS_EXPR,
- arg1, TREE_OPERAND (arg0, 1), 0))
- && ! TREE_CONSTANT_OVERFLOW (tem))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
-
- /* Likewise, we can simplify a comparison of a real constant with
- a MINUS_EXPR whose first operand is also a real constant, i.e.
- (c1 - x) < c2 becomes x > c1-c2. */
- if (flag_unsafe_math_optimizations
- && TREE_CODE (arg1) == REAL_CST
- && TREE_CODE (arg0) == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
- && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
- arg1, 0))
- && ! TREE_CONSTANT_OVERFLOW (tem))
- return fold_build2 (swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 1), tem);
-
- /* Fold comparisons against built-in math functions. */
- if (TREE_CODE (arg1) == REAL_CST
- && flag_unsafe_math_optimizations
- && ! flag_errno_math)
- {
- enum built_in_function fcode = builtin_mathfn_code (arg0);
-
- if (fcode != END_BUILTINS)
- {
- tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
- if (tem != NULL_TREE)
- return tem;
- }
- }
- }
-
- /* Convert foo++ == CONST into ++foo == CONST + INCR. */
- if (TREE_CONSTANT (arg1)
- && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
- || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
- /* This optimization is invalid for ordered comparisons
- if CONST+INCR overflows or if foo+incr might overflow.
- This optimization is invalid for floating point due to rounding.
- For pointer types we assume overflow doesn't happen. */
- && (POINTER_TYPE_P (TREE_TYPE (arg0))
- || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
- && (code == EQ_EXPR || code == NE_EXPR))))
- {
- tree varop, newconst;
-
- if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
- {
- newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
- arg1, TREE_OPERAND (arg0, 1));
- varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg0, 1));
- }
- else
- {
- newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
- arg1, TREE_OPERAND (arg0, 1));
- varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg0, 1));
- }
-
-
- /* If VAROP is a reference to a bitfield, we must mask
- the constant by the width of the field. */
- if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
- && host_integerp (DECL_SIZE (TREE_OPERAND
- (TREE_OPERAND (varop, 0), 1)), 1))
- {
- tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
- HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
- tree folded_compare, shift;
-
- /* First check whether the comparison would come out
- always the same. If we don't do that we would
- change the meaning with the masking. */
- folded_compare = fold_build2 (code, type,
- TREE_OPERAND (varop, 0), arg1);
- if (integer_zerop (folded_compare)
- || integer_onep (folded_compare))
- return omit_one_operand (type, folded_compare, varop);
-
- shift = build_int_cst (NULL_TREE,
- TYPE_PRECISION (TREE_TYPE (varop)) - size);
- shift = fold_convert (TREE_TYPE (varop), shift);
- newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
- newconst, shift);
- newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
- newconst, shift);
- }
-
- return fold_build2 (code, type, varop, newconst);
- }
-
/* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
This transformation affects the cases which are handled in later
optimizations involving comparisons with non-negative constants. */
--- 9853,9858 ----
*************** fold_binary (enum tree_code code, tree t
*** 9428,9449 ****
&& TREE_CODE (arg0) != INTEGER_CST
&& tree_int_cst_sgn (arg1) > 0)
{
! switch (code)
{
- case GE_EXPR:
arg1 = const_binop (MINUS_EXPR, arg1,
build_int_cst (TREE_TYPE (arg1), 1), 0);
return fold_build2 (GT_EXPR, type, arg0,
fold_convert (TREE_TYPE (arg0), arg1));
!
! case LT_EXPR:
arg1 = const_binop (MINUS_EXPR, arg1,
build_int_cst (TREE_TYPE (arg1), 1), 0);
return fold_build2 (LE_EXPR, type, arg0,
fold_convert (TREE_TYPE (arg0), arg1));
-
- default:
- break;
}
}
--- 9860,9878 ----
&& TREE_CODE (arg0) != INTEGER_CST
&& tree_int_cst_sgn (arg1) > 0)
{
! if (code == GE_EXPR)
{
arg1 = const_binop (MINUS_EXPR, arg1,
build_int_cst (TREE_TYPE (arg1), 1), 0);
return fold_build2 (GT_EXPR, type, arg0,
fold_convert (TREE_TYPE (arg0), arg1));
! }
! if (code == LT_EXPR)
! {
arg1 = const_binop (MINUS_EXPR, arg1,
build_int_cst (TREE_TYPE (arg1), 1), 0);
return fold_build2 (LE_EXPR, type, arg0,
fold_convert (TREE_TYPE (arg0), arg1));
}
}
*************** fold_binary (enum tree_code code, tree t
*** 9596,9673 ****
}
}
- /* If this is an EQ or NE comparison of a constant with a PLUS_EXPR or
- a MINUS_EXPR of a constant, we can convert it into a comparison with
- a revised constant as long as no overflow occurs. */
- if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg1) == INTEGER_CST
- && (TREE_CODE (arg0) == PLUS_EXPR
- || TREE_CODE (arg0) == MINUS_EXPR)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
- ? MINUS_EXPR : PLUS_EXPR,
- arg1, TREE_OPERAND (arg0, 1), 0))
- && ! TREE_CONSTANT_OVERFLOW (tem))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
-
- /* Similarly for a NEGATE_EXPR. */
- else if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == NEGATE_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && 0 != (tem = negate_expr (arg1))
- && TREE_CODE (tem) == INTEGER_CST
- && ! TREE_CONSTANT_OVERFLOW (tem))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
-
- /* If we have X - Y == 0, we can convert that to X == Y and similarly
- for !=. Don't do this for ordered comparisons due to overflow. */
- else if ((code == NE_EXPR || code == EQ_EXPR)
- && integer_zerop (arg1) && TREE_CODE (arg0) == MINUS_EXPR)
- return fold_build2 (code, type,
- TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
-
- else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
- && (TREE_CODE (arg0) == NOP_EXPR
- || TREE_CODE (arg0) == CONVERT_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. */
- else if (TREE_CODE (arg1) == INTEGER_CST
- && (TREE_CODE (arg0) == MIN_EXPR
- || TREE_CODE (arg0) == MAX_EXPR)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tem = optimize_minmax_comparison (code, type, op0, op1);
- if (tem)
- return tem;
-
- return NULL_TREE;
- }
-
/* If we are comparing an ABS_EXPR with a constant, we can
convert all the cases into explicit comparisons, but they may
well not be faster than doing the ABS and one comparison.
But ABS (X) <= C is a range comparison, which becomes a subtraction
and a comparison, and is probably faster. */
! else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST
! && TREE_CODE (arg0) == ABS_EXPR
! && ! TREE_SIDE_EFFECTS (arg0)
! && (0 != (tem = negate_expr (arg1)))
! && TREE_CODE (tem) == INTEGER_CST
! && ! TREE_CONSTANT_OVERFLOW (tem))
return fold_build2 (TRUTH_ANDIF_EXPR, type,
build2 (GE_EXPR, type,
TREE_OPERAND (arg0, 0), tem),
--- 10025,10042 ----
}
}
/* If we are comparing an ABS_EXPR with a constant, we can
convert all the cases into explicit comparisons, but they may
well not be faster than doing the ABS and one comparison.
But ABS (X) <= C is a range comparison, which becomes a subtraction
and a comparison, and is probably faster. */
! if (code == LE_EXPR
! && TREE_CODE (arg1) == INTEGER_CST
! && TREE_CODE (arg0) == ABS_EXPR
! && ! TREE_SIDE_EFFECTS (arg0)
! && (0 != (tem = negate_expr (arg1)))
! && TREE_CODE (tem) == INTEGER_CST
! && ! TREE_CONSTANT_OVERFLOW (tem))
return fold_build2 (TRUTH_ANDIF_EXPR, type,
build2 (GE_EXPR, type,
TREE_OPERAND (arg0, 0), tem),
*************** fold_binary (enum tree_code code, tree t
*** 9675,9809 ****
TREE_OPERAND (arg0, 0), arg1));
/* Convert ABS_EXPR<x> >= 0 to true. */
! else if (code == GE_EXPR
! && tree_expr_nonnegative_p (arg0)
! && (integer_zerop (arg1)
! || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
! && real_zerop (arg1))))
return omit_one_operand (type, integer_one_node, arg0);
/* Convert ABS_EXPR<x> < 0 to false. */
! else if (code == LT_EXPR
! && tree_expr_nonnegative_p (arg0)
! && (integer_zerop (arg1) || real_zerop (arg1)))
return omit_one_operand (type, integer_zero_node, arg0);
- /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */
- else if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == ABS_EXPR
- && (integer_zerop (arg1) || real_zerop (arg1)))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0), arg1);
-
- /* If this is an EQ or NE comparison with zero and ARG0 is
- (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
- two operations, but the latter can be done in one less insn
- on machines that have only two-operand insns or on which a
- constant cannot be the first operand. */
- if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == BIT_AND_EXPR)
- {
- tree arg00 = TREE_OPERAND (arg0, 0);
- tree arg01 = TREE_OPERAND (arg0, 1);
- if (TREE_CODE (arg00) == LSHIFT_EXPR
- && integer_onep (TREE_OPERAND (arg00, 0)))
- return
- fold_build2 (code, type,
- build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
- arg01, TREE_OPERAND (arg00, 1)),
- fold_convert (TREE_TYPE (arg0),
- integer_one_node)),
- arg1);
- else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR
- && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0)))
- return
- fold_build2 (code, type,
- build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
- arg00, TREE_OPERAND (arg01, 1)),
- fold_convert (TREE_TYPE (arg0),
- integer_one_node)),
- arg1);
- }
-
- /* If this is an NE or EQ comparison of zero against the result of a
- signed MOD operation whose second operand is a power of 2, make
- the MOD operation unsigned since it is simpler and equivalent. */
- if ((code == NE_EXPR || code == EQ_EXPR)
- && integer_zerop (arg1)
- && !TYPE_UNSIGNED (TREE_TYPE (arg0))
- && (TREE_CODE (arg0) == TRUNC_MOD_EXPR
- || TREE_CODE (arg0) == CEIL_MOD_EXPR
- || TREE_CODE (arg0) == FLOOR_MOD_EXPR
- || TREE_CODE (arg0) == ROUND_MOD_EXPR)
- && integer_pow2p (TREE_OPERAND (arg0, 1)))
- {
- tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
- tree newmod = fold_build2 (TREE_CODE (arg0), newtype,
- fold_convert (newtype,
- TREE_OPERAND (arg0, 0)),
- fold_convert (newtype,
- TREE_OPERAND (arg0, 1)));
-
- return fold_build2 (code, type, newmod,
- fold_convert (newtype, arg1));
- }
-
- /* If this is an NE comparison of zero with an AND of one, remove the
- comparison since the AND will give the correct value. */
- if (code == NE_EXPR && integer_zerop (arg1)
- && TREE_CODE (arg0) == BIT_AND_EXPR
- && integer_onep (TREE_OPERAND (arg0, 1)))
- return fold_convert (type, arg0);
-
- /* If we have (A & C) == C where C is a power of 2, convert this into
- (A & C) != 0. Similarly for NE_EXPR. */
- if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == BIT_AND_EXPR
- && integer_pow2p (TREE_OPERAND (arg0, 1))
- && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
- arg0, fold_convert (TREE_TYPE (arg0),
- integer_zero_node));
-
- /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
- bit, then fold the expression into A < 0 or A >= 0. */
- tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type);
- if (tem)
- return tem;
-
- /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
- Similarly for NE_EXPR. */
- if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tree notc = fold_build1 (BIT_NOT_EXPR,
- TREE_TYPE (TREE_OPERAND (arg0, 1)),
- TREE_OPERAND (arg0, 1));
- tree dandnotc = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- arg1, notc);
- tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
- if (integer_nonzerop (dandnotc))
- return omit_one_operand (type, rslt, arg0);
- }
-
- /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
- Similarly for NE_EXPR. */
- if ((code == EQ_EXPR || code == NE_EXPR)
- && TREE_CODE (arg0) == BIT_IOR_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
- tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- TREE_OPERAND (arg0, 1), notd);
- tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
- if (integer_nonzerop (candnotd))
- return omit_one_operand (type, rslt, arg0);
- }
-
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
if ((code == LT_EXPR || code == GE_EXPR)
--- 10044,10062 ----
TREE_OPERAND (arg0, 0), arg1));
/* Convert ABS_EXPR<x> >= 0 to true. */
! if (code == GE_EXPR
! && tree_expr_nonnegative_p (arg0)
! && (integer_zerop (arg1)
! || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
! && real_zerop (arg1))))
return omit_one_operand (type, integer_one_node, arg0);
/* Convert ABS_EXPR<x> < 0 to false. */
! if (code == LT_EXPR
! && tree_expr_nonnegative_p (arg0)
! && (integer_zerop (arg1) || real_zerop (arg1)))
return omit_one_operand (type, integer_zero_node, arg0);
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
if ((code == LT_EXPR || code == GE_EXPR)
*************** fold_binary (enum tree_code code, tree t
*** 9815,9826 ****
TREE_OPERAND (arg1, 1)),
build_int_cst (TREE_TYPE (arg0), 0));
! else if ((code == LT_EXPR || code == GE_EXPR)
! && TYPE_UNSIGNED (TREE_TYPE (arg0))
! && (TREE_CODE (arg1) == NOP_EXPR
! || TREE_CODE (arg1) == CONVERT_EXPR)
! && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
! && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
return
build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
fold_convert (TREE_TYPE (arg0),
--- 10068,10079 ----
TREE_OPERAND (arg1, 1)),
build_int_cst (TREE_TYPE (arg0), 0));
! if ((code == LT_EXPR || code == GE_EXPR)
! && TYPE_UNSIGNED (TREE_TYPE (arg0))
! && (TREE_CODE (arg1) == NOP_EXPR
! || TREE_CODE (arg1) == CONVERT_EXPR)
! && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
! && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
return
build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
fold_convert (TREE_TYPE (arg0),
*************** fold_binary (enum tree_code code, tree t
*** 9829,10081 ****
1))),
build_int_cst (TREE_TYPE (arg0), 0));
! /* Simplify comparison of something with itself. (For IEEE
! floating-point, we can only do some of these simplifications.) */
! if (operand_equal_p (arg0, arg1, 0))
! {
! switch (code)
! {
! case EQ_EXPR:
! if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
! || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
! return constant_boolean_node (1, type);
! break;
!
! case GE_EXPR:
! case LE_EXPR:
! if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
! || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
! return constant_boolean_node (1, type);
! return fold_build2 (EQ_EXPR, type, arg0, arg1);
!
! case NE_EXPR:
! /* For NE, we can only do this simplification if integer
! or we don't honor IEEE floating point NaNs. */
! if (FLOAT_TYPE_P (TREE_TYPE (arg0))
! && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
! break;
! /* ... fall through ... */
! case GT_EXPR:
! case LT_EXPR:
! return constant_boolean_node (0, type);
! default:
! gcc_unreachable ();
! }
! }
!
! /* If we are comparing an expression that just has comparisons
! of two integer values, arithmetic expressions of those comparisons,
! and constants, we can simplify it. There are only three cases
! to check: the two values can either be equal, the first can be
! greater, or the second can be greater. Fold the expression for
! those three values. Since each value must be 0 or 1, we have
! eight possibilities, each of which corresponds to the constant 0
! or 1 or one of the six possible comparisons.
!
! This handles common cases like (a > b) == 0 but also handles
! expressions like ((x > y) - (y > x)) > 0, which supposedly
! occur in macroized code. */
!
! if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST)
! {
! tree cval1 = 0, cval2 = 0;
! int save_p = 0;
!
! if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p)
! /* Don't handle degenerate cases here; they should already
! have been handled anyway. */
! && cval1 != 0 && cval2 != 0
! && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
! && TREE_TYPE (cval1) == TREE_TYPE (cval2)
! && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
! && TYPE_MAX_VALUE (TREE_TYPE (cval1))
! && TYPE_MAX_VALUE (TREE_TYPE (cval2))
! && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
! TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
! {
! tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1));
! tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1));
!
! /* We can't just pass T to eval_subst in case cval1 or cval2
! was the same as ARG1. */
!
! tree high_result
! = fold_build2 (code, type,
! eval_subst (arg0, cval1, maxval,
! cval2, minval),
! arg1);
! tree equal_result
! = fold_build2 (code, type,
! eval_subst (arg0, cval1, maxval,
! cval2, maxval),
! arg1);
! tree low_result
! = fold_build2 (code, type,
! eval_subst (arg0, cval1, minval,
! cval2, maxval),
! arg1);
!
! /* All three of these results should be 0 or 1. Confirm they
! are. Then use those values to select the proper code
! to use. */
!
! if ((integer_zerop (high_result)
! || integer_onep (high_result))
! && (integer_zerop (equal_result)
! || integer_onep (equal_result))
! && (integer_zerop (low_result)
! || integer_onep (low_result)))
! {
! /* Make a 3-bit mask with the high-order bit being the
! value for `>', the next for '=', and the low for '<'. */
! switch ((integer_onep (high_result) * 4)
! + (integer_onep (equal_result) * 2)
! + integer_onep (low_result))
! {
! case 0:
! /* Always false. */
! return omit_one_operand (type, integer_zero_node, arg0);
! case 1:
! code = LT_EXPR;
! break;
! case 2:
! code = EQ_EXPR;
! break;
! case 3:
! code = LE_EXPR;
! break;
! case 4:
! code = GT_EXPR;
! break;
! case 5:
! code = NE_EXPR;
! break;
! case 6:
! code = GE_EXPR;
! break;
! case 7:
! /* Always true. */
! return omit_one_operand (type, integer_one_node, arg0);
! }
!
! if (save_p)
! return save_expr (build2 (code, type, cval1, cval2));
! else
! return fold_build2 (code, type, cval1, cval2);
! }
! }
! }
!
! /* If this is a comparison of a field, we may be able to simplify it. */
! if (((TREE_CODE (arg0) == COMPONENT_REF
! && lang_hooks.can_use_bit_fields_p ())
! || TREE_CODE (arg0) == BIT_FIELD_REF)
! && (code == EQ_EXPR || code == NE_EXPR)
! /* Handle the constant case even without -O
! to make sure the warnings are given. */
! && (optimize || TREE_CODE (arg1) == INTEGER_CST))
! {
! t1 = optimize_bit_field_compare (code, type, arg0, arg1);
! if (t1)
! return t1;
! }
!
! /* Fold a comparison of the address of COMPONENT_REFs with the same
! type and component to a comparison of the address of the base
! object. In short, &x->a OP &y->a to x OP y and
! &x->a OP &y.a to x OP &y */
! if (TREE_CODE (arg0) == ADDR_EXPR
! && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
! && TREE_CODE (arg1) == ADDR_EXPR
! && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
! {
! tree cref0 = TREE_OPERAND (arg0, 0);
! tree cref1 = TREE_OPERAND (arg1, 0);
! if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
! {
! tree op0 = TREE_OPERAND (cref0, 0);
! tree op1 = TREE_OPERAND (cref1, 0);
! return fold_build2 (code, type,
! build_fold_addr_expr (op0),
! build_fold_addr_expr (op1));
! }
! }
!
! /* Optimize comparisons of strlen vs zero to a compare of the
! first character of the string vs zero. To wit,
! strlen(ptr) == 0 => *ptr == 0
! strlen(ptr) != 0 => *ptr != 0
! Other cases should reduce to one of these two (or a constant)
! due to the return value of strlen being unsigned. */
! if ((code == EQ_EXPR || code == NE_EXPR)
! && integer_zerop (arg1)
! && TREE_CODE (arg0) == CALL_EXPR)
! {
! tree fndecl = get_callee_fndecl (arg0);
! tree arglist;
!
! if (fndecl
! && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
! && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
! && (arglist = TREE_OPERAND (arg0, 1))
! && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
! && ! TREE_CHAIN (arglist))
! {
! tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
! return fold_build2 (code, type, iref,
! build_int_cst (TREE_TYPE (iref), 0));
! }
! }
!
! /* We can fold X/C1 op C2 where C1 and C2 are integer constants
! into a single range test. */
! if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
! || TREE_CODE (arg0) == EXACT_DIV_EXPR)
! && TREE_CODE (arg1) == INTEGER_CST
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && !integer_zerop (TREE_OPERAND (arg0, 1))
! && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
! && !TREE_OVERFLOW (arg1))
! {
! t1 = fold_div_compare (code, type, arg0, arg1);
! if (t1 != NULL_TREE)
! return t1;
! }
!
! /* Fold (X >> C) != 0 into X < 0 if C is one less than the width
! of X. Similarly fold (X >> C) == 0 into X >= 0. */
! if ((code == EQ_EXPR || code == NE_EXPR)
! && integer_zerop (arg1)
! && TREE_CODE (arg0) == RSHIFT_EXPR
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
! {
! tree arg00 = TREE_OPERAND (arg0, 0);
! tree arg01 = TREE_OPERAND (arg0, 1);
! tree itype = TREE_TYPE (arg00);
! if (TREE_INT_CST_HIGH (arg01) == 0
! && TREE_INT_CST_LOW (arg01)
! == (unsigned HOST_WIDE_INT) (TYPE_PRECISION (itype) - 1))
! {
! if (TYPE_UNSIGNED (itype))
! {
! itype = lang_hooks.types.signed_type (itype);
! arg00 = fold_convert (itype, arg00);
! }
! return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
! type, arg00, build_int_cst (itype, 0));
! }
! }
!
! if ((code == EQ_EXPR || code == NE_EXPR)
! && integer_zerop (arg1)
! && tree_expr_nonzero_p (arg0))
! {
! tree res = constant_boolean_node (code==NE_EXPR, type);
! return omit_one_operand (type, res, arg0);
! }
!
! t1 = fold_relational_const (code, type, arg0, arg1);
! return t1 == NULL_TREE ? NULL_TREE : t1;
case UNORDERED_EXPR:
case ORDERED_EXPR:
--- 10082,10088 ----
1))),
build_int_cst (TREE_TYPE (arg0), 0));
! return NULL_TREE;
case UNORDERED_EXPR:
case ORDERED_EXPR:
Roger
--