fold-const.c (fold_comparison): Clean up and extend X +- C1 CMP C2 to X CMP C2 -+ C1 transformation to...

* 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) <EQ_EXPR/NE_EXPR>: Remove same transformations.

From-SVN: r210979
This commit is contained in:
Eric Botcazou 2014-05-27 19:54:46 +00:00 committed by Eric Botcazou
parent 3ce6c71537
commit d378c07ebb
5 changed files with 83 additions and 57 deletions

View File

@ -1,3 +1,10 @@
2014-05-27 Eric Botcazou <ebotcazou@adacore.com>
* 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) <EQ_EXPR/NE_EXPR>: Remove same transformations.
2014-05-27 Segher Boessenkool <segher@kernel.crashing.org> 2014-05-27 Segher Boessenkool <segher@kernel.crashing.org>
* stmt.c (dump_case_nodes): Don't convert values to HOST_WIDE_INT * stmt.c (dump_case_nodes): Don't convert values to HOST_WIDE_INT

View File

@ -8904,6 +8904,7 @@ static tree
fold_comparison (location_t loc, enum tree_code code, tree type, fold_comparison (location_t loc, enum tree_code code, tree type,
tree op0, tree op1) tree op0, tree op1)
{ {
const bool equality_code = (code == EQ_EXPR || code == NE_EXPR);
tree arg0, arg1, tem; tree arg0, arg1, tem;
arg0 = op0; 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)) if (tree_swap_operands_p (arg0, arg1, true))
return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0); 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) if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
&& (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST && (equality_code || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
&& !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) && TREE_CODE (arg1) == INTEGER_CST
&& (TREE_CODE (arg1) == INTEGER_CST && !TREE_OVERFLOW (arg1))
&& !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 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 variable = TREE_OPERAND (arg0, 0);
tree lhs; tree new_const = int_const_binop (reverse_op, const2, const1);
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);
/* If the constant operation overflowed this can be /* If the constant operation overflowed this can be
simplified as a comparison against INT_MAX/INT_MIN. */ simplified as a comparison against INT_MAX/INT_MIN. */
if (TREE_CODE (lhs) == INTEGER_CST if (TREE_OVERFLOW (new_const))
&& TREE_OVERFLOW (lhs))
{ {
int const1_sgn = tree_int_cst_sgn (const1); int const1_sgn = tree_int_cst_sgn (const1);
enum tree_code code2 = code; 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 /* We now can look at the canonicalized case
VARIABLE + 1 CODE2 INT_MIN VARIABLE + 1 CODE2 INT_MIN
and decide on the result. */ and decide on the result. */
if (code2 == LT_EXPR switch (code2)
|| 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);
}
if (TREE_CODE (lhs) == TREE_CODE (arg1)
&& (TREE_CODE (lhs) != INTEGER_CST
|| !TREE_OVERFLOW (lhs)))
{ {
if (code != EQ_EXPR && code != NE_EXPR) case EQ_EXPR:
case LT_EXPR:
case LE_EXPR:
return
omit_one_operand_loc (loc, type, boolean_false_node, variable);
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 (!equality_code)
fold_overflow_warning ("assuming signed overflow does not occur " fold_overflow_warning ("assuming signed overflow does not occur "
"when changing X +- C1 cmp C2 to " "when changing X +- C1 cmp C2 to "
"X cmp C1 +- C2", "X cmp C2 -+ C1",
WARN_STRICT_OVERFLOW_COMPARISON); 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 /* For comparisons of pointers we can decompose it to a compile time
comparison of the base objects and the offsets into the object. comparison of the base objects and the offsets into the object.
This requires at least one operand being an ADDR_EXPR or a 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)) || POINTER_TYPE_OVERFLOW_UNDEFINED))
{ {
if (code != EQ_EXPR if (!equality_code
&& code != NE_EXPR
&& bitpos0 != bitpos1 && bitpos0 != bitpos1
&& (pointer_may_wrap_p (base0, offset0, bitpos0) && (pointer_may_wrap_p (base0, offset0, bitpos0)
|| pointer_may_wrap_p (base1, offset1, bitpos1))) || 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 object and overflow on pointer differences is undefined as of
6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */
else if (bitpos0 == bitpos1 else if (bitpos0 == bitpos1
&& ((code == EQ_EXPR || code == NE_EXPR) && (equality_code
|| (indirect_base0 && DECL_P (base0)) || (indirect_base0 && DECL_P (base0))
|| POINTER_TYPE_OVERFLOW_UNDEFINED)) || POINTER_TYPE_OVERFLOW_UNDEFINED))
{ {
@ -9164,8 +9179,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
else else
offset1 = fold_convert_loc (loc, ssizetype, offset1); offset1 = fold_convert_loc (loc, ssizetype, offset1);
if (code != EQ_EXPR if (!equality_code
&& code != NE_EXPR
&& (pointer_may_wrap_p (base0, offset0, bitpos0) && (pointer_may_wrap_p (base0, offset0, bitpos0)
|| pointer_may_wrap_p (base1, offset1, bitpos1))) || pointer_may_wrap_p (base1, offset1, bitpos1)))
fold_overflow_warning (("assuming pointer wraparound does not " fold_overflow_warning (("assuming pointer wraparound does not "
@ -12888,21 +12902,6 @@ fold_binary_loc (location_t loc,
type); 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. */ /* Similarly for a NEGATE_EXPR. */
if (TREE_CODE (arg0) == NEGATE_EXPR if (TREE_CODE (arg0) == NEGATE_EXPR
&& TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST
@ -12956,13 +12955,6 @@ fold_binary_loc (location_t loc,
TREE_OPERAND (arg0, 1), arg1); 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<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */ /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */
if (TREE_CODE (arg0) == ABS_EXPR if (TREE_CODE (arg0) == ABS_EXPR
&& (integer_zerop (arg1) || real_zerop (arg1))) && (integer_zerop (arg1) || real_zerop (arg1)))

View File

@ -1,3 +1,8 @@
2014-05-27 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/fold-compare-8.c: New test.
* gcc.dg/Wstrict-overflow-25.c: Likewise.
2014-05-27 Richard Biener <rguenther@suse.de> 2014-05-27 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/vrp92.c: New testcase. * gcc.dg/tree-ssa/vrp92.c: New testcase.

View File

@ -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" } */
}

View File

@ -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" } } */