@@ -7127,11 +7127,13 @@ fold_binary_op_with_conditional_arg (location_t loc,
}
-/* Subroutine of fold() that checks for the addition of +/- 0.0.
+/* Subroutine of fold() that checks for the addition of ARG +/- 0.0.
- If !NEGATE, return true if ADDEND is +/-0.0 and, for all X of type
- TYPE, X + ADDEND is the same as X. If NEGATE, return true if X -
- ADDEND is the same as X.
+ If !NEGATE, return true if ZERO_ARG is +/-0.0 and, for all ARG of
+ type TYPE, ARG + ZERO_ARG is the same as ARG. If NEGATE, return true
+ if ARG - ZERO_ARG is the same as X.
+
+ If ARG is NULL, check for any value of type TYPE.
X + 0 and X - 0 both give X when X is NaN, infinite, or nonzero
and finite. The problematic cases are when X is zero, and its mode
@@ -7140,13 +7142,14 @@ fold_binary_op_with_conditional_arg (location_t loc,
modes, X + 0 is not the same as X because -0 + 0 is 0. */
bool
-fold_real_zero_addition_p (const_tree type, const_tree addend, int negate)
+fold_real_zero_addition_p (const_tree type, const_tree arg,
+ const_tree zero_arg, int negate)
{
- if (!real_zerop (addend))
+ if (!real_zerop (zero_arg))
return false;
/* Don't allow the fold with -fsignaling-nans. */
- if (HONOR_SNANS (type))
+ if (arg ? tree_expr_maybe_signaling_nan_p (arg) : HONOR_SNANS (type))
return false;
/* Allow the fold if zeros aren't signed, or their sign isn't important. */
@@ -7158,19 +7161,20 @@ fold_real_zero_addition_p (const_tree type, const_tree addend, int negate)
return false;
/* In a vector or complex, we would need to check the sign of all zeros. */
- if (TREE_CODE (addend) == VECTOR_CST)
- addend = uniform_vector_p (addend);
- if (!addend || TREE_CODE (addend) != REAL_CST)
+ if (TREE_CODE (zero_arg) == VECTOR_CST)
+ zero_arg = uniform_vector_p (zero_arg);
+ if (!zero_arg || TREE_CODE (zero_arg) != REAL_CST)
return false;
/* Treat x + -0 as x - 0 and x - -0 as x + 0. */
- if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (addend)))
+ if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (zero_arg)))
negate = !negate;
/* The mode has signed zeros, and we have to honor their sign.
- In this situation, there is only one case we can return true for.
- X - 0 is the same as X with default rounding. */
- return negate;
+ In this situation, there are only two cases we can return true for.
+ (i) X - 0 is the same as X with default rounding.
+ (ii) X + 0 is X when X can't possibly be -0.0. */
+ return negate || (arg && !tree_expr_maybe_real_minus_zero_p (arg));
}
/* Subroutine of match.pd that optimizes comparisons of a division by
@@ -14375,6 +14379,44 @@ tree_expr_maybe_nan_p (const_tree x)
}
}
+/* Return true if expression X could evaluate to -0.0.
+ This function returns true if uncertain. */
+
+bool
+tree_expr_maybe_real_minus_zero_p (const_tree x)
+{
+ if (!HONOR_SIGNED_ZEROS (x))
+ return false;
+ switch (TREE_CODE (x))
+ {
+ case REAL_CST:
+ return REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (x));
+ case INTEGER_CST:
+ case FLOAT_EXPR:
+ case ABS_EXPR:
+ return false;
+ case NON_LVALUE_EXPR:
+ case SAVE_EXPR:
+ return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 0));
+ case COND_EXPR:
+ return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 1))
+ || tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 2));
+ case CALL_EXPR:
+ switch (get_call_combined_fn (x))
+ {
+ CASE_CFN_FABS:
+ return false;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ /* Ideally !(tree_expr_nonzero_p (X) || tree_expr_nonnegative_p (X))
+ * but currently those predicates require tree and not const_tree. */
+ return true;
+}
+
#define tree_expr_nonnegative_warnv_p(X, Y) \
_Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
@@ -164,7 +164,8 @@ extern bool integer_valued_real_call_p (combined_fn, tree, tree, int);
extern bool integer_valued_real_single_p (tree, int);
extern bool integer_valued_real_p (tree, int = 0);
-extern bool fold_real_zero_addition_p (const_tree, const_tree, int);
+extern bool fold_real_zero_addition_p (const_tree, const_tree, const_tree,
+ int);
extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
enum tree_code, tree, tree, tree);
extern void debug_fold_checksum (const_tree);
@@ -195,6 +196,7 @@ extern bool tree_expr_signaling_nan_p (const_tree);
extern bool tree_expr_maybe_signaling_nan_p (const_tree);
extern bool tree_expr_nan_p (const_tree);
extern bool tree_expr_maybe_nan_p (const_tree);
+extern bool tree_maybe_real_minus_zero_p (const_tree);
extern tree make_range (tree, int *, tree *, tree *, bool *);
extern tree make_range_step (location_t, enum tree_code, tree, tree, tree,
tree *, tree *, int *, bool *);
@@ -152,13 +152,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
Likewise if the operands are reversed. */
(simplify
(plus:c @0 real_zerop@1)
- (if (fold_real_zero_addition_p (type, @1, 0))
+ (if (fold_real_zero_addition_p (type, @0, @1, 0))
(non_lvalue @0)))
/* See if ARG1 is zero and X - ARG1 reduces to X. */
(simplify
(minus @0 real_zerop@1)
- (if (fold_real_zero_addition_p (type, @1, 1))
+ (if (fold_real_zero_addition_p (type, @0, @1, 1))
(non_lvalue @0)))
/* Even if the fold_real_zero_addition_p can't simplify X + 0.0
@@ -190,7 +190,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
is volatile. */
(simplify
(minus @0 @0)
- (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
+ (if (!FLOAT_TYPE_P (type) || !tree_expr_maybe_nan_p (@0))
{ build_zero_cst (type); }))
(simplify
(pointer_diff @@0 @0)
@@ -206,14 +206,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
negative value by 0 gives -0, not +0. */
(simplify
(mult @0 real_zerop@1)
- (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
+ (if (!tree_expr_maybe_nan_p (@0)
+ && !tree_expr_maybe_real_minus_zero_p (@0)
+ && !tree_expr_maybe_real_minus_zero_p (@1))
@1))
/* In IEEE floating point, x*1 is not equivalent to x for snans.
Likewise for complex arithmetic with signed zeros. */
(simplify
(mult @0 real_onep)
- (if (!HONOR_SNANS (type)
+ (if (!tree_expr_maybe_signaling_nan_p (@0)
&& (!HONOR_SIGNED_ZEROS (type)
|| !COMPLEX_FLOAT_TYPE_P (type)))
(non_lvalue @0)))
@@ -221,7 +223,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Transform x * -1.0 into -x. */
(simplify
(mult @0 real_minus_onep)
- (if (!HONOR_SNANS (type)
+ (if (!tree_expr_maybe_signaling_nan_p (@0)
&& (!HONOR_SIGNED_ZEROS (type)
|| !COMPLEX_FLOAT_TYPE_P (type)))
(negate @0)))
@@ -259,7 +261,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Transform X * (X <= 0.0 ? 1.0 : -1.0) into -abs(X). */
(simplify
(mult:c @0 (cond (cmp @0 real_zerop) real_onep@1 real_minus_onep))
- (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
+ (if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
(outp (abs @0))))
/* Transform X * (X > 0.0 ? -1.0 : 1.0) into -abs(X). */
/* Transform X * (X >= 0.0 ? -1.0 : 1.0) into -abs(X). */
@@ -267,19 +269,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Transform X * (X <= 0.0 ? -1.0 : 1.0) into abs(X). */
(simplify
(mult:c @0 (cond (cmp @0 real_zerop) real_minus_onep real_onep@1))
- (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
+ (if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
(outn (abs @0)))))
/* Transform X * copysign (1.0, X) into abs(X). */
(simplify
(mult:c @0 (COPYSIGN_ALL real_onep @0))
- (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
+ (if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
(abs @0)))
/* Transform X * copysign (1.0, -X) into -abs(X). */
(simplify
(mult:c @0 (COPYSIGN_ALL real_onep (negate @0)))
- (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
+ (if (!tree_expr_maybe_nan_p (@0) && !HONOR_SIGNED_ZEROS (type))
(negate (abs @0))))
/* Transform copysign (CST, X) into copysign (ABS(CST), X). */
@@ -444,13 +446,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* In IEEE floating point, x/1 is not equivalent to x for snans. */
(simplify
(rdiv @0 real_onep)
- (if (!HONOR_SNANS (type))
+ (if (!tree_expr_maybe_signaling_nan_p (@0))
(non_lvalue @0)))
/* In IEEE floating point, x/-1 is not equivalent to -x for snans. */
(simplify
(rdiv @0 real_minus_onep)
- (if (!HONOR_SNANS (type))
+ (if (!tree_expr_maybe_signaling_nan_p (@0))
(negate @0)))
(if (flag_reciprocal_math)
@@ -3543,7 +3545,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(-ARG1 + ARG0) reduces to -ARG1. */
(simplify
(minus real_zerop@0 @1)
- (if (fold_real_zero_addition_p (type, @0, 0))
+ (if (fold_real_zero_addition_p (type, @1, @0, 0))
(negate @1)))
/* Transform x * -1 into -x. */
@@ -1062,7 +1062,7 @@ eliminate_using_constants (enum tree_code opcode,
if (integer_zerop (oelast->op)
|| (FLOAT_TYPE_P (type)
&& (opcode == PLUS_EXPR || opcode == MINUS_EXPR)
- && fold_real_zero_addition_p (type, oelast->op,
+ && fold_real_zero_addition_p (type, 0, oelast->op,
opcode == MINUS_EXPR)))
{
if (ops->length () != 1)