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:
parent
3ce6c71537
commit
d378c07ebb
|
@ -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
|
||||||
|
|
106
gcc/fold-const.c
106
gcc/fold-const.c
|
@ -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)))
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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" } */
|
||||||
|
}
|
|
@ -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" } } */
|
Loading…
Reference in New Issue