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>
|
2014-11-11 Uros Bizjak <ubizjak@gmail.com>
|
||||||
|
|
||||||
* system.h: Include algorithm and utility.
|
* system.h: Include algorithm and utility.
|
||||||
|
|
|
||||||
|
|
@ -9939,59 +9939,8 @@ fold_binary_loc (location_t loc,
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
case PLUS_EXPR:
|
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))
|
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. */
|
/* X + (X / CST) * -CST is X % CST. */
|
||||||
if (TREE_CODE (arg1) == MULT_EXPR
|
if (TREE_CODE (arg1) == MULT_EXPR
|
||||||
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_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);
|
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. */
|
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
|
||||||
if (TREE_CODE (arg0) == NEGATE_EXPR
|
if (TREE_CODE (arg0) == NEGATE_EXPR
|
||||||
&& negate_expr_p (arg1)
|
&& 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. */
|
/* Generic tree predicates we inherit. */
|
||||||
(define_predicates
|
(define_predicates
|
||||||
integer_onep integer_zerop integer_all_onesp
|
integer_onep integer_zerop integer_all_onesp integer_minus_onep
|
||||||
real_zerop real_onep
|
integer_each_onep
|
||||||
|
real_zerop real_onep real_minus_onep
|
||||||
CONSTANT_CLASS_P
|
CONSTANT_CLASS_P
|
||||||
tree_expr_nonnegative_p)
|
tree_expr_nonnegative_p)
|
||||||
|
|
||||||
|
|
@ -239,10 +240,6 @@ along with GCC; see the file COPYING3. If not see
|
||||||
(bit_not (bit_not @0))
|
(bit_not (bit_not @0))
|
||||||
@0)
|
@0)
|
||||||
|
|
||||||
(simplify
|
|
||||||
(negate (negate @0))
|
|
||||||
@0)
|
|
||||||
|
|
||||||
|
|
||||||
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
|
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
|
||||||
(simplify
|
(simplify
|
||||||
|
|
@ -278,6 +275,116 @@ along with GCC; see the file COPYING3. If not see
|
||||||
(bit_and @0 { algn; })))
|
(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. */
|
/* Simplifications of conversions. */
|
||||||
|
|
||||||
/* Basic strip-useless-type-conversions / strip_nops. */
|
/* Basic strip-useless-type-conversions / strip_nops. */
|
||||||
|
|
|
||||||
|
|
@ -1920,359 +1920,6 @@ simplify_rotate (gimple_stmt_iterator *gsi)
|
||||||
return true;
|
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
|
/* Combine an element access with a shuffle. Returns true if there were
|
||||||
any changes made, else it returns false. */
|
any changes made, else it returns false. */
|
||||||
|
|
||||||
|
|
@ -2805,14 +2452,6 @@ pass_forwprop::execute (function *fun)
|
||||||
|| code == BIT_XOR_EXPR)
|
|| code == BIT_XOR_EXPR)
|
||||||
&& simplify_rotate (&gsi))
|
&& simplify_rotate (&gsi))
|
||||||
changed = true;
|
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)
|
else if (code == VEC_PERM_EXPR)
|
||||||
{
|
{
|
||||||
int did_something = simplify_permutation (&gsi);
|
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
|
/* Return true iff conversion in EXP generates no instruction. Mark
|
||||||
it inline so that we fully inline into the stripping functions even
|
it inline so that we fully inline into the stripping functions even
|
||||||
though we have two uses of this function. */
|
though we have two uses of this function. */
|
||||||
|
|
@ -11680,19 +11701,7 @@ tree_nop_conversion (const_tree exp)
|
||||||
if (!inner_type)
|
if (!inner_type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Use precision rather then machine mode when we can, which gives
|
return tree_nop_conversion_p (outer_type, inner_type);
|
||||||
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. Don't
|
/* 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 typedef_variant_p (tree);
|
||||||
extern bool auto_var_in_fn_p (const_tree, const_tree);
|
extern bool auto_var_in_fn_p (const_tree, const_tree);
|
||||||
extern tree build_low_bits_mask (tree, unsigned);
|
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_nop_conversions (tree);
|
||||||
extern tree tree_strip_sign_nop_conversions (tree);
|
extern tree tree_strip_sign_nop_conversions (tree);
|
||||||
extern const_tree strip_invariant_refs (const_tree);
|
extern const_tree strip_invariant_refs (const_tree);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue