mirror of git://gcc.gnu.org/git/gcc.git
match.pd: Implement patterns from associate_plusminus and factor in differences from the...
2014-11-11 Richard Biener <rguenther@suse.de> * match.pd: Implement patterns from associate_plusminus and factor in differences from the fold-const.c implementation. * fold-const.c (fold_binary_loc): Remove patterns here. * tree-ssa-forwprop.c (associate_plusminus): Remove. (pass_forwprop::execute): Don't call it. * tree.c (tree_nop_conversion_p): New function, factored from tree_nop_conversion. * tree.h (tree_nop_conversion_p): Declare. From-SVN: r217349
This commit is contained in:
parent
9310366b70
commit
cc7b5acf37
|
|
@ -1,3 +1,14 @@
|
|||
2014-11-11 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* match.pd: Implement patterns from associate_plusminus
|
||||
and factor in differences from the fold-const.c implementation.
|
||||
* fold-const.c (fold_binary_loc): Remove patterns here.
|
||||
* tree-ssa-forwprop.c (associate_plusminus): Remove.
|
||||
(pass_forwprop::execute): Don't call it.
|
||||
* tree.c (tree_nop_conversion_p): New function, factored
|
||||
from tree_nop_conversion.
|
||||
* tree.h (tree_nop_conversion_p): Declare.
|
||||
|
||||
2014-11-11 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* system.h: Include algorithm and utility.
|
||||
|
|
|
|||
|
|
@ -9939,59 +9939,8 @@ fold_binary_loc (location_t loc,
|
|||
return NULL_TREE;
|
||||
|
||||
case PLUS_EXPR:
|
||||
/* A + (-B) -> A - B */
|
||||
if (TREE_CODE (arg1) == NEGATE_EXPR
|
||||
&& (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
|
||||
return fold_build2_loc (loc, MINUS_EXPR, type,
|
||||
fold_convert_loc (loc, type, arg0),
|
||||
fold_convert_loc (loc, type,
|
||||
TREE_OPERAND (arg1, 0)));
|
||||
/* (-A) + B -> B - A */
|
||||
if (TREE_CODE (arg0) == NEGATE_EXPR
|
||||
&& reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)
|
||||
&& (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
|
||||
return fold_build2_loc (loc, MINUS_EXPR, type,
|
||||
fold_convert_loc (loc, type, arg1),
|
||||
fold_convert_loc (loc, type,
|
||||
TREE_OPERAND (arg0, 0)));
|
||||
|
||||
if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
|
||||
{
|
||||
/* Convert ~A + 1 to -A. */
|
||||
if (TREE_CODE (arg0) == BIT_NOT_EXPR
|
||||
&& integer_each_onep (arg1))
|
||||
return fold_build1_loc (loc, NEGATE_EXPR, type,
|
||||
fold_convert_loc (loc, type,
|
||||
TREE_OPERAND (arg0, 0)));
|
||||
|
||||
/* ~X + X is -1. */
|
||||
if (TREE_CODE (arg0) == BIT_NOT_EXPR
|
||||
&& !TYPE_OVERFLOW_TRAPS (type))
|
||||
{
|
||||
tree tem = TREE_OPERAND (arg0, 0);
|
||||
|
||||
STRIP_NOPS (tem);
|
||||
if (operand_equal_p (tem, arg1, 0))
|
||||
{
|
||||
t1 = build_all_ones_cst (type);
|
||||
return omit_one_operand_loc (loc, type, t1, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
/* X + ~X is -1. */
|
||||
if (TREE_CODE (arg1) == BIT_NOT_EXPR
|
||||
&& !TYPE_OVERFLOW_TRAPS (type))
|
||||
{
|
||||
tree tem = TREE_OPERAND (arg1, 0);
|
||||
|
||||
STRIP_NOPS (tem);
|
||||
if (operand_equal_p (arg0, tem, 0))
|
||||
{
|
||||
t1 = build_all_ones_cst (type);
|
||||
return omit_one_operand_loc (loc, type, t1, arg0);
|
||||
}
|
||||
}
|
||||
|
||||
/* X + (X / CST) * -CST is X % CST. */
|
||||
if (TREE_CODE (arg1) == MULT_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR
|
||||
|
|
@ -10469,11 +10418,6 @@ fold_binary_loc (location_t loc,
|
|||
return fold_build2_loc (loc, MINUS_EXPR, type, tmp, arg11);
|
||||
}
|
||||
}
|
||||
/* A - (-B) -> A + B */
|
||||
if (TREE_CODE (arg1) == NEGATE_EXPR)
|
||||
return fold_build2_loc (loc, PLUS_EXPR, type, op0,
|
||||
fold_convert_loc (loc, type,
|
||||
TREE_OPERAND (arg1, 0)));
|
||||
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
|
||||
if (TREE_CODE (arg0) == NEGATE_EXPR
|
||||
&& negate_expr_p (arg1)
|
||||
|
|
|
|||
119
gcc/match.pd
119
gcc/match.pd
|
|
@ -25,8 +25,9 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
/* Generic tree predicates we inherit. */
|
||||
(define_predicates
|
||||
integer_onep integer_zerop integer_all_onesp
|
||||
real_zerop real_onep
|
||||
integer_onep integer_zerop integer_all_onesp integer_minus_onep
|
||||
integer_each_onep
|
||||
real_zerop real_onep real_minus_onep
|
||||
CONSTANT_CLASS_P
|
||||
tree_expr_nonnegative_p)
|
||||
|
||||
|
|
@ -239,10 +240,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
(bit_not (bit_not @0))
|
||||
@0)
|
||||
|
||||
(simplify
|
||||
(negate (negate @0))
|
||||
@0)
|
||||
|
||||
|
||||
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
|
||||
(simplify
|
||||
|
|
@ -278,6 +275,116 @@ along with GCC; see the file COPYING3. If not see
|
|||
(bit_and @0 { algn; })))
|
||||
|
||||
|
||||
/* We can't reassociate at all for saturating types. */
|
||||
(if (!TYPE_SATURATING (type))
|
||||
|
||||
/* Contract negates. */
|
||||
/* A + (-B) -> A - B */
|
||||
(simplify
|
||||
(plus:c (convert1? @0) (convert2? (negate @1)))
|
||||
/* Apply STRIP_NOPS on @0 and the negate. */
|
||||
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
|
||||
&& tree_nop_conversion_p (type, TREE_TYPE (@1))
|
||||
&& (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
|
||||
(minus (convert @0) (convert @1))))
|
||||
/* A - (-B) -> A + B */
|
||||
(simplify
|
||||
(minus (convert1? @0) (convert2? (negate @1)))
|
||||
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
|
||||
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
|
||||
(plus (convert @0) (convert @1))))
|
||||
/* -(-A) -> A */
|
||||
(simplify
|
||||
(negate (convert? (negate @1)))
|
||||
(if (tree_nop_conversion_p (type, TREE_TYPE (@1))
|
||||
&& (TYPE_OVERFLOW_WRAPS (type)
|
||||
|| (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0))
|
||||
@1))
|
||||
|
||||
/* We can't reassociate floating-point or fixed-point plus or minus
|
||||
because of saturation to +-Inf. */
|
||||
(if (!FLOAT_TYPE_P (type) && !FIXED_POINT_TYPE_P (type))
|
||||
|
||||
/* Match patterns that allow contracting a plus-minus pair
|
||||
irrespective of overflow issues. */
|
||||
/* (A +- B) - A -> +- B */
|
||||
/* (A +- B) -+ B -> A */
|
||||
/* A - (A +- B) -> -+ B */
|
||||
/* A +- (B -+ A) -> +- B */
|
||||
(simplify
|
||||
(minus (plus:c @0 @1) @0)
|
||||
@1)
|
||||
(simplify
|
||||
(minus (minus @0 @1) @0)
|
||||
(negate @1))
|
||||
(simplify
|
||||
(plus:c (minus @0 @1) @1)
|
||||
@0)
|
||||
(simplify
|
||||
(minus @0 (plus:c @0 @1))
|
||||
(negate @1))
|
||||
(simplify
|
||||
(minus @0 (minus @0 @1))
|
||||
@1)
|
||||
|
||||
/* (A +- CST) +- CST -> A + CST */
|
||||
(for outer_op (plus minus)
|
||||
(for inner_op (plus minus)
|
||||
(simplify
|
||||
(outer_op (inner_op @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
|
||||
/* If the constant operation overflows we cannot do the transform
|
||||
as we would introduce undefined overflow, for example
|
||||
with (a - 1) + INT_MIN. */
|
||||
(with { tree cst = fold_binary (outer_op == inner_op
|
||||
? PLUS_EXPR : MINUS_EXPR, type, @1, @2); }
|
||||
(if (cst && !TREE_OVERFLOW (cst))
|
||||
(inner_op @0 { cst; } ))))))
|
||||
|
||||
/* (CST - A) +- CST -> CST - A */
|
||||
(for outer_op (plus minus)
|
||||
(simplify
|
||||
(outer_op (minus CONSTANT_CLASS_P@1 @0) CONSTANT_CLASS_P@2)
|
||||
(with { tree cst = fold_binary (outer_op, type, @1, @2); }
|
||||
(if (cst && !TREE_OVERFLOW (cst))
|
||||
(minus { cst; } @0)))))
|
||||
|
||||
/* ~A + A -> -1 */
|
||||
(simplify
|
||||
(plus:c (bit_not @0) @0)
|
||||
(if (!TYPE_OVERFLOW_TRAPS (type))
|
||||
{ build_all_ones_cst (type); }))
|
||||
|
||||
/* ~A + 1 -> -A */
|
||||
(simplify
|
||||
(plus (bit_not @0) integer_each_onep)
|
||||
(negate @0))
|
||||
|
||||
/* (T)(P + A) - (T)P -> (T) A */
|
||||
(for add (plus pointer_plus)
|
||||
(simplify
|
||||
(minus (convert (add @0 @1))
|
||||
(convert @0))
|
||||
(if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1))
|
||||
/* For integer types, if A has a smaller type
|
||||
than T the result depends on the possible
|
||||
overflow in P + A.
|
||||
E.g. T=size_t, A=(unsigned)429497295, P>0.
|
||||
However, if an overflow in P + A would cause
|
||||
undefined behavior, we can assume that there
|
||||
is no overflow. */
|
||||
|| (INTEGRAL_TYPE_P (TREE_TYPE (@0))
|
||||
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
|
||||
/* For pointer types, if the conversion of A to the
|
||||
final type requires a sign- or zero-extension,
|
||||
then we have to punt - it is not defined which
|
||||
one is correct. */
|
||||
|| (POINTER_TYPE_P (TREE_TYPE (@0))
|
||||
&& TREE_CODE (@1) == INTEGER_CST
|
||||
&& tree_int_cst_sign_bit (@1) == 0))
|
||||
(convert @1))))))
|
||||
|
||||
|
||||
|
||||
/* Simplifications of conversions. */
|
||||
|
||||
/* Basic strip-useless-type-conversions / strip_nops. */
|
||||
|
|
|
|||
|
|
@ -1920,359 +1920,6 @@ simplify_rotate (gimple_stmt_iterator *gsi)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Perform re-associations of the plus or minus statement STMT that are
|
||||
always permitted. Returns true if the CFG was changed. */
|
||||
|
||||
static bool
|
||||
associate_plusminus (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
tree rhs2 = gimple_assign_rhs2 (stmt);
|
||||
enum tree_code code = gimple_assign_rhs_code (stmt);
|
||||
bool changed;
|
||||
|
||||
/* We can't reassociate at all for saturating types. */
|
||||
if (TYPE_SATURATING (TREE_TYPE (rhs1)))
|
||||
return false;
|
||||
|
||||
/* First contract negates. */
|
||||
do
|
||||
{
|
||||
changed = false;
|
||||
|
||||
/* A +- (-B) -> A -+ B. */
|
||||
if (TREE_CODE (rhs2) == SSA_NAME)
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (rhs2);
|
||||
if (is_gimple_assign (def_stmt)
|
||||
&& gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR
|
||||
&& can_propagate_from (def_stmt))
|
||||
{
|
||||
code = (code == MINUS_EXPR) ? PLUS_EXPR : MINUS_EXPR;
|
||||
gimple_assign_set_rhs_code (stmt, code);
|
||||
rhs2 = gimple_assign_rhs1 (def_stmt);
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* (-A) + B -> B - A. */
|
||||
if (TREE_CODE (rhs1) == SSA_NAME
|
||||
&& code == PLUS_EXPR)
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
|
||||
if (is_gimple_assign (def_stmt)
|
||||
&& gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR
|
||||
&& can_propagate_from (def_stmt))
|
||||
{
|
||||
code = MINUS_EXPR;
|
||||
gimple_assign_set_rhs_code (stmt, code);
|
||||
rhs1 = rhs2;
|
||||
gimple_assign_set_rhs1 (stmt, rhs1);
|
||||
rhs2 = gimple_assign_rhs1 (def_stmt);
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (changed);
|
||||
|
||||
/* We can't reassociate floating-point or fixed-point plus or minus
|
||||
because of saturation to +-Inf. */
|
||||
if (FLOAT_TYPE_P (TREE_TYPE (rhs1))
|
||||
|| FIXED_POINT_TYPE_P (TREE_TYPE (rhs1)))
|
||||
goto out;
|
||||
|
||||
/* Second match patterns that allow contracting a plus-minus pair
|
||||
irrespective of overflow issues.
|
||||
|
||||
(A +- B) - A -> +- B
|
||||
(A +- B) -+ B -> A
|
||||
(CST +- A) +- CST -> CST +- A
|
||||
(A +- CST) +- CST -> A +- CST
|
||||
~A + A -> -1
|
||||
~A + 1 -> -A
|
||||
A - (A +- B) -> -+ B
|
||||
A +- (B +- A) -> +- B
|
||||
CST +- (CST +- A) -> CST +- A
|
||||
CST +- (A +- CST) -> CST +- A
|
||||
A + ~A -> -1
|
||||
(T)(P + A) - (T)P -> (T)A
|
||||
|
||||
via commutating the addition and contracting operations to zero
|
||||
by reassociation. */
|
||||
|
||||
if (TREE_CODE (rhs1) == SSA_NAME)
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
|
||||
if (is_gimple_assign (def_stmt) && can_propagate_from (def_stmt))
|
||||
{
|
||||
enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
|
||||
if (def_code == PLUS_EXPR
|
||||
|| def_code == MINUS_EXPR)
|
||||
{
|
||||
tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
|
||||
tree def_rhs2 = gimple_assign_rhs2 (def_stmt);
|
||||
if (operand_equal_p (def_rhs1, rhs2, 0)
|
||||
&& code == MINUS_EXPR)
|
||||
{
|
||||
/* (A +- B) - A -> +- B. */
|
||||
code = ((def_code == PLUS_EXPR)
|
||||
? TREE_CODE (def_rhs2) : NEGATE_EXPR);
|
||||
rhs1 = def_rhs2;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
else if (operand_equal_p (def_rhs2, rhs2, 0)
|
||||
&& code != def_code)
|
||||
{
|
||||
/* (A +- B) -+ B -> A. */
|
||||
code = TREE_CODE (def_rhs1);
|
||||
rhs1 = def_rhs1;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
else if (CONSTANT_CLASS_P (rhs2)
|
||||
&& CONSTANT_CLASS_P (def_rhs1))
|
||||
{
|
||||
/* (CST +- A) +- CST -> CST +- A. */
|
||||
tree cst = fold_binary (code, TREE_TYPE (rhs1),
|
||||
def_rhs1, rhs2);
|
||||
if (cst && !TREE_OVERFLOW (cst))
|
||||
{
|
||||
code = def_code;
|
||||
gimple_assign_set_rhs_code (stmt, code);
|
||||
rhs1 = cst;
|
||||
gimple_assign_set_rhs1 (stmt, rhs1);
|
||||
rhs2 = def_rhs2;
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
else if (CONSTANT_CLASS_P (rhs2)
|
||||
&& CONSTANT_CLASS_P (def_rhs2))
|
||||
{
|
||||
/* (A +- CST) +- CST -> A +- CST. */
|
||||
enum tree_code mix = (code == def_code)
|
||||
? PLUS_EXPR : MINUS_EXPR;
|
||||
tree cst = fold_binary (mix, TREE_TYPE (rhs1),
|
||||
def_rhs2, rhs2);
|
||||
if (cst && !TREE_OVERFLOW (cst))
|
||||
{
|
||||
code = def_code;
|
||||
gimple_assign_set_rhs_code (stmt, code);
|
||||
rhs1 = def_rhs1;
|
||||
gimple_assign_set_rhs1 (stmt, rhs1);
|
||||
rhs2 = cst;
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (def_code == BIT_NOT_EXPR && code == PLUS_EXPR)
|
||||
{
|
||||
tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
|
||||
if (operand_equal_p (def_rhs1, rhs2, 0))
|
||||
{
|
||||
/* ~A + A -> -1. */
|
||||
rhs1 = build_all_ones_cst (TREE_TYPE (rhs2));
|
||||
rhs2 = NULL_TREE;
|
||||
code = TREE_CODE (rhs1);
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
else if ((TREE_CODE (TREE_TYPE (rhs2)) != COMPLEX_TYPE
|
||||
&& integer_onep (rhs2))
|
||||
|| (TREE_CODE (rhs2) == COMPLEX_CST
|
||||
&& integer_onep (TREE_REALPART (rhs2))
|
||||
&& integer_onep (TREE_IMAGPART (rhs2))))
|
||||
{
|
||||
/* ~A + 1 -> -A. */
|
||||
code = NEGATE_EXPR;
|
||||
rhs1 = def_rhs1;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
else if (code == MINUS_EXPR
|
||||
&& CONVERT_EXPR_CODE_P (def_code)
|
||||
&& TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
|
||||
&& TREE_CODE (rhs2) == SSA_NAME)
|
||||
{
|
||||
/* (T)(P + A) - (T)P -> (T)A. */
|
||||
gimple def_stmt2 = SSA_NAME_DEF_STMT (rhs2);
|
||||
if (is_gimple_assign (def_stmt2)
|
||||
&& can_propagate_from (def_stmt2)
|
||||
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2))
|
||||
&& TREE_CODE (gimple_assign_rhs1 (def_stmt2)) == SSA_NAME)
|
||||
{
|
||||
/* Now we have (T)X - (T)P. */
|
||||
tree p = gimple_assign_rhs1 (def_stmt2);
|
||||
def_stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def_stmt));
|
||||
if (is_gimple_assign (def_stmt2)
|
||||
&& can_propagate_from (def_stmt2)
|
||||
&& (gimple_assign_rhs_code (def_stmt2) == POINTER_PLUS_EXPR
|
||||
|| gimple_assign_rhs_code (def_stmt2) == PLUS_EXPR)
|
||||
&& gimple_assign_rhs1 (def_stmt2) == p)
|
||||
{
|
||||
/* And finally (T)(P + A) - (T)P. */
|
||||
tree a = gimple_assign_rhs2 (def_stmt2);
|
||||
if (TYPE_PRECISION (TREE_TYPE (rhs1))
|
||||
<= TYPE_PRECISION (TREE_TYPE (a))
|
||||
/* For integer types, if A has a smaller type
|
||||
than T the result depends on the possible
|
||||
overflow in P + A.
|
||||
E.g. T=size_t, A=(unsigned)429497295, P>0.
|
||||
However, if an overflow in P + A would cause
|
||||
undefined behavior, we can assume that there
|
||||
is no overflow. */
|
||||
|| (INTEGRAL_TYPE_P (TREE_TYPE (p))
|
||||
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (p)))
|
||||
/* For pointer types, if the conversion of A to the
|
||||
final type requires a sign- or zero-extension,
|
||||
then we have to punt - it is not defined which
|
||||
one is correct. */
|
||||
|| (POINTER_TYPE_P (TREE_TYPE (p))
|
||||
&& TREE_CODE (a) == INTEGER_CST
|
||||
&& tree_int_cst_sign_bit (a) == 0))
|
||||
{
|
||||
if (issue_strict_overflow_warning
|
||||
(WARN_STRICT_OVERFLOW_MISC)
|
||||
&& TYPE_PRECISION (TREE_TYPE (rhs1))
|
||||
> TYPE_PRECISION (TREE_TYPE (a))
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (p)))
|
||||
warning_at (gimple_location (stmt),
|
||||
OPT_Wstrict_overflow,
|
||||
"assuming signed overflow does not "
|
||||
"occur when assuming that "
|
||||
"(T)(P + A) - (T)P is always (T)A");
|
||||
if (useless_type_conversion_p (TREE_TYPE (rhs1),
|
||||
TREE_TYPE (a)))
|
||||
code = TREE_CODE (a);
|
||||
else
|
||||
code = NOP_EXPR;
|
||||
rhs1 = a;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1,
|
||||
rhs2);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rhs2 && TREE_CODE (rhs2) == SSA_NAME)
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (rhs2);
|
||||
if (is_gimple_assign (def_stmt) && can_propagate_from (def_stmt))
|
||||
{
|
||||
enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
|
||||
if (def_code == PLUS_EXPR
|
||||
|| def_code == MINUS_EXPR)
|
||||
{
|
||||
tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
|
||||
tree def_rhs2 = gimple_assign_rhs2 (def_stmt);
|
||||
if (operand_equal_p (def_rhs1, rhs1, 0)
|
||||
&& code == MINUS_EXPR)
|
||||
{
|
||||
/* A - (A +- B) -> -+ B. */
|
||||
code = ((def_code == PLUS_EXPR)
|
||||
? NEGATE_EXPR : TREE_CODE (def_rhs2));
|
||||
rhs1 = def_rhs2;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
else if (operand_equal_p (def_rhs2, rhs1, 0)
|
||||
&& code != def_code)
|
||||
{
|
||||
/* A +- (B +- A) -> +- B. */
|
||||
code = ((code == PLUS_EXPR)
|
||||
? TREE_CODE (def_rhs1) : NEGATE_EXPR);
|
||||
rhs1 = def_rhs1;
|
||||
rhs2 = NULL_TREE;
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
else if (CONSTANT_CLASS_P (rhs1)
|
||||
&& CONSTANT_CLASS_P (def_rhs1))
|
||||
{
|
||||
/* CST +- (CST +- A) -> CST +- A. */
|
||||
tree cst = fold_binary (code, TREE_TYPE (rhs2),
|
||||
rhs1, def_rhs1);
|
||||
if (cst && !TREE_OVERFLOW (cst))
|
||||
{
|
||||
code = (code == def_code ? PLUS_EXPR : MINUS_EXPR);
|
||||
gimple_assign_set_rhs_code (stmt, code);
|
||||
rhs1 = cst;
|
||||
gimple_assign_set_rhs1 (stmt, rhs1);
|
||||
rhs2 = def_rhs2;
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
else if (CONSTANT_CLASS_P (rhs1)
|
||||
&& CONSTANT_CLASS_P (def_rhs2))
|
||||
{
|
||||
/* CST +- (A +- CST) -> CST +- A. */
|
||||
tree cst = fold_binary (def_code == code
|
||||
? PLUS_EXPR : MINUS_EXPR,
|
||||
TREE_TYPE (rhs2),
|
||||
rhs1, def_rhs2);
|
||||
if (cst && !TREE_OVERFLOW (cst))
|
||||
{
|
||||
rhs1 = cst;
|
||||
gimple_assign_set_rhs1 (stmt, rhs1);
|
||||
rhs2 = def_rhs1;
|
||||
gimple_assign_set_rhs2 (stmt, rhs2);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (def_code == BIT_NOT_EXPR)
|
||||
{
|
||||
tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
|
||||
if (code == PLUS_EXPR
|
||||
&& operand_equal_p (def_rhs1, rhs1, 0))
|
||||
{
|
||||
/* A + ~A -> -1. */
|
||||
rhs1 = build_all_ones_cst (TREE_TYPE (rhs1));
|
||||
rhs2 = NULL_TREE;
|
||||
code = TREE_CODE (rhs1);
|
||||
gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
|
||||
gcc_assert (gsi_stmt (*gsi) == stmt);
|
||||
gimple_set_modified (stmt, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (gimple_modified_p (stmt))
|
||||
{
|
||||
fold_stmt_inplace (gsi);
|
||||
update_stmt (stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Combine an element access with a shuffle. Returns true if there were
|
||||
any changes made, else it returns false. */
|
||||
|
||||
|
|
@ -2805,14 +2452,6 @@ pass_forwprop::execute (function *fun)
|
|||
|| code == BIT_XOR_EXPR)
|
||||
&& simplify_rotate (&gsi))
|
||||
changed = true;
|
||||
else if (code == PLUS_EXPR
|
||||
|| code == MINUS_EXPR)
|
||||
{
|
||||
changed = associate_plusminus (&gsi);
|
||||
if (changed
|
||||
&& maybe_clean_or_replace_eh_stmt (stmt, stmt))
|
||||
bitmap_set_bit (to_purge, bb->index);
|
||||
}
|
||||
else if (code == VEC_PERM_EXPR)
|
||||
{
|
||||
int did_something = simplify_permutation (&gsi);
|
||||
|
|
|
|||
35
gcc/tree.c
35
gcc/tree.c
|
|
@ -11659,6 +11659,27 @@ block_ultimate_origin (const_tree block)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true iff conversion from INNER_TYPE to OUTER_TYPE generates
|
||||
no instruction. */
|
||||
|
||||
bool
|
||||
tree_nop_conversion_p (const_tree outer_type, const_tree inner_type)
|
||||
{
|
||||
/* Use precision rather then machine mode when we can, which gives
|
||||
the correct answer even for submode (bit-field) types. */
|
||||
if ((INTEGRAL_TYPE_P (outer_type)
|
||||
|| POINTER_TYPE_P (outer_type)
|
||||
|| TREE_CODE (outer_type) == OFFSET_TYPE)
|
||||
&& (INTEGRAL_TYPE_P (inner_type)
|
||||
|| POINTER_TYPE_P (inner_type)
|
||||
|| TREE_CODE (inner_type) == OFFSET_TYPE))
|
||||
return TYPE_PRECISION (outer_type) == TYPE_PRECISION (inner_type);
|
||||
|
||||
/* Otherwise fall back on comparing machine modes (e.g. for
|
||||
aggregate types, floats). */
|
||||
return TYPE_MODE (outer_type) == TYPE_MODE (inner_type);
|
||||
}
|
||||
|
||||
/* Return true iff conversion in EXP generates no instruction. Mark
|
||||
it inline so that we fully inline into the stripping functions even
|
||||
though we have two uses of this function. */
|
||||
|
|
@ -11680,19 +11701,7 @@ tree_nop_conversion (const_tree exp)
|
|||
if (!inner_type)
|
||||
return false;
|
||||
|
||||
/* Use precision rather then machine mode when we can, which gives
|
||||
the correct answer even for submode (bit-field) types. */
|
||||
if ((INTEGRAL_TYPE_P (outer_type)
|
||||
|| POINTER_TYPE_P (outer_type)
|
||||
|| TREE_CODE (outer_type) == OFFSET_TYPE)
|
||||
&& (INTEGRAL_TYPE_P (inner_type)
|
||||
|| POINTER_TYPE_P (inner_type)
|
||||
|| TREE_CODE (inner_type) == OFFSET_TYPE))
|
||||
return TYPE_PRECISION (outer_type) == TYPE_PRECISION (inner_type);
|
||||
|
||||
/* Otherwise fall back on comparing machine modes (e.g. for
|
||||
aggregate types, floats). */
|
||||
return TYPE_MODE (outer_type) == TYPE_MODE (inner_type);
|
||||
return tree_nop_conversion_p (outer_type, inner_type);
|
||||
}
|
||||
|
||||
/* Return true iff conversion in EXP generates no instruction. Don't
|
||||
|
|
|
|||
|
|
@ -4226,6 +4226,7 @@ extern bool is_typedef_decl (tree x);
|
|||
extern bool typedef_variant_p (tree);
|
||||
extern bool auto_var_in_fn_p (const_tree, const_tree);
|
||||
extern tree build_low_bits_mask (tree, unsigned);
|
||||
extern bool tree_nop_conversion_p (const_tree, const_tree);
|
||||
extern tree tree_strip_nop_conversions (tree);
|
||||
extern tree tree_strip_sign_nop_conversions (tree);
|
||||
extern const_tree strip_invariant_refs (const_tree);
|
||||
|
|
|
|||
Loading…
Reference in New Issue