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
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)
/* 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)
(bit_not (bit_not @0))
@0)
-(simplify
- (negate (negate @0))
- @0)
-
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
(simplify
(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. */
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. */
|| 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);