diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5d322f080b2..9b8621e767b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-05-27 Eric Botcazou + + * fold-const.c (fold_comparison): Clean up and extend X +- C1 CMP C2 + to X CMP C2 -+ C1 transformation to EQ_EXPR/NE_EXPR. + Add X - Y CMP 0 to X CMP Y transformation. + (fold_binary_loc) : Remove same transformations. + 2014-05-27 Segher Boessenkool * stmt.c (dump_case_nodes): Don't convert values to HOST_WIDE_INT diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 188b179bb78..b3009340e3e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8904,6 +8904,7 @@ static tree fold_comparison (location_t loc, enum tree_code code, tree type, tree op0, tree op1) { + const bool equality_code = (code == EQ_EXPR || code == NE_EXPR); tree arg0, arg1, tem; arg0 = op0; @@ -8920,28 +8921,24 @@ fold_comparison (location_t loc, enum tree_code code, tree type, if (tree_swap_operands_p (arg0, arg1, true)) return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0); - /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1. */ + /* 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_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) - && (TREE_CODE (arg1) == INTEGER_CST - && !TREE_OVERFLOW (arg1))) + && (equality_code || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) + && TREE_CODE (arg1) == INTEGER_CST + && !TREE_OVERFLOW (arg1)) { + const enum tree_code + reverse_op = TREE_CODE (arg0) == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR; tree const1 = TREE_OPERAND (arg0, 1); - tree const2 = arg1; + tree const2 = fold_convert_loc (loc, TREE_TYPE (const1), arg1); tree variable = TREE_OPERAND (arg0, 0); - tree lhs; - int lhs_add; - lhs_add = TREE_CODE (arg0) != PLUS_EXPR; - - lhs = fold_build2_loc (loc, lhs_add ? PLUS_EXPR : MINUS_EXPR, - TREE_TYPE (arg1), const2, const1); + tree new_const = int_const_binop (reverse_op, const2, const1); /* If the constant operation overflowed this can be simplified as a comparison against INT_MAX/INT_MIN. */ - if (TREE_CODE (lhs) == INTEGER_CST - && TREE_OVERFLOW (lhs)) + if (TREE_OVERFLOW (new_const)) { int const1_sgn = tree_int_cst_sgn (const1); enum tree_code code2 = code; @@ -8961,29 +8958,48 @@ fold_comparison (location_t loc, enum tree_code code, tree type, /* We now can look at the canonicalized case VARIABLE + 1 CODE2 INT_MIN and decide on the result. */ - if (code2 == LT_EXPR - || code2 == LE_EXPR - || code2 == EQ_EXPR) - return omit_one_operand_loc (loc, type, boolean_false_node, variable); - else if (code2 == NE_EXPR - || code2 == GE_EXPR - || code2 == GT_EXPR) - return omit_one_operand_loc (loc, type, boolean_true_node, variable); - } + switch (code2) + { + case EQ_EXPR: + case LT_EXPR: + case LE_EXPR: + return + omit_one_operand_loc (loc, type, boolean_false_node, variable); - if (TREE_CODE (lhs) == TREE_CODE (arg1) - && (TREE_CODE (lhs) != INTEGER_CST - || !TREE_OVERFLOW (lhs))) + case NE_EXPR: + case GE_EXPR: + case GT_EXPR: + return + omit_one_operand_loc (loc, type, boolean_true_node, variable); + + default: + gcc_unreachable (); + } + } + else { - if (code != EQ_EXPR && code != NE_EXPR) + if (!equality_code) fold_overflow_warning ("assuming signed overflow does not occur " "when changing X +- C1 cmp C2 to " - "X cmp C1 +- C2", + "X cmp C2 -+ C1", WARN_STRICT_OVERFLOW_COMPARISON); - return fold_build2_loc (loc, code, type, variable, lhs); + return fold_build2_loc (loc, code, type, variable, new_const); } } + /* Transform comparisons of the form X - Y CMP 0 to X CMP Y. */ + if (TREE_CODE (arg0) == MINUS_EXPR + && (equality_code || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))) + && integer_zerop (arg1)) + { + if (!equality_code) + fold_overflow_warning ("assuming signed overflow does not occur " + "when changing X - Y cmp 0 to X cmp Y", + WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1)); + } + /* For comparisons of pointers we can decompose it to a compile time comparison of the base objects and the offsets into the object. This requires at least one operand being an ADDR_EXPR or a @@ -9111,8 +9127,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, || POINTER_TYPE_OVERFLOW_UNDEFINED)) { - if (code != EQ_EXPR - && code != NE_EXPR + if (!equality_code && bitpos0 != bitpos1 && (pointer_may_wrap_p (base0, offset0, bitpos0) || pointer_may_wrap_p (base1, offset1, bitpos1))) @@ -9146,7 +9161,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, object and overflow on pointer differences is undefined as of 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ else if (bitpos0 == bitpos1 - && ((code == EQ_EXPR || code == NE_EXPR) + && (equality_code || (indirect_base0 && DECL_P (base0)) || POINTER_TYPE_OVERFLOW_UNDEFINED)) { @@ -9164,8 +9179,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, else offset1 = fold_convert_loc (loc, ssizetype, offset1); - if (code != EQ_EXPR - && code != NE_EXPR + if (!equality_code && (pointer_may_wrap_p (base0, offset0, bitpos0) || pointer_may_wrap_p (base1, offset1, bitpos1))) fold_overflow_warning (("assuming pointer wraparound does not " @@ -12888,21 +12902,6 @@ fold_binary_loc (location_t loc, 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, - fold_convert_loc (loc, TREE_TYPE (arg0), - arg1), - TREE_OPERAND (arg0, 1))) - && !TREE_OVERFLOW (tem)) - return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem); - /* Similarly for a NEGATE_EXPR. */ if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == INTEGER_CST @@ -12956,13 +12955,6 @@ fold_binary_loc (location_t loc, TREE_OPERAND (arg0, 1), arg1); } - /* 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_loc (loc, code, type, - TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)); - /* Convert ABS_EXPR == 0 or ABS_EXPR != 0 to x == 0 or x != 0. */ if (TREE_CODE (arg0) == ABS_EXPR && (integer_zerop (arg1) || real_zerop (arg1))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3a185ca136a..e1e70c1b267 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-05-27 Eric Botcazou + + * gcc.dg/fold-compare-8.c: New test. + * gcc.dg/Wstrict-overflow-25.c: Likewise. + 2014-05-27 Richard Biener * gcc.dg/tree-ssa/vrp92.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c new file mode 100644 index 00000000000..00916446371 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */ + +/* We can only simplify the conditional when using strict overflow + semantics. */ + +int +foo (int x, int y) +{ + return x - y < 0; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */ +} diff --git a/gcc/testsuite/gcc.dg/fold-compare-8.c b/gcc/testsuite/gcc.dg/fold-compare-8.c new file mode 100644 index 00000000000..b6e42fdef10 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-compare-8.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-original" } */ + +int +foo (int x, int y) +{ + return x - y < 0; +} + +/* { dg-final { scan-tree-dump "x < y" "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */