summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/builtins.c15
-rw-r--r--gcc/c-common.c152
-rw-r--r--gcc/combine.c21
-rw-r--r--gcc/cse.c25
-rw-r--r--gcc/defaults.h20
-rw-r--r--gcc/doc/tm.texi49
-rw-r--r--gcc/flags.h23
-rw-r--r--gcc/fold-const.c174
-rw-r--r--gcc/ifcvt.c9
-rw-r--r--gcc/jump.c14
-rw-r--r--gcc/simplify-rtx.c63
12 files changed, 408 insertions, 187 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6def6705e0b..2940fceffa3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+2002-03-07 Richard Sandiford <rsandifo@redhat.com>
+
+ * defaults.h (MODE_HAS_NANS, MODE_HAS_INFINITIES): New.
+ (MODE_HAS_SIGNED_ZEROS, MODE_HAS_SIGN_DEPENDENT_ROUNDING): New.
+ * flags.h (HONOR_NANS, HONOR_INFINITIES, HONOR_SIGNED_ZEROS): New.
+ (HONOR_SIGN_DEPENDENT_ROUNDING): New.
+ * builtins.c (expand_builtin_mathfn): Use HONOR_NANS.
+ * c-common.c (truthvalue_conversion): Reduce x - y != 0 to x != y
+ unless x and y could be infinite.
+ (expand_unordered_cmp): New, mostly split from expand_tree_builtin.
+ Check that the common type of both arguments is a real, even for
+ targets without unordered comparisons. Allow an integer argument
+ to be compared against a real.
+ (expand_tree_builtin): Use expand_unordered_cmp.
+ * combine.c (combine_simplify_rtx): Use the new HONOR_... macros.
+ * cse.c (fold_rtx): Likewise. Fix indentation.
+ * fold-const.c (fold_real_zero_addition_p): New.
+ (fold): Use it, and the new HONOR_... macros.
+ * ifcvt.c (noce_try_minmax): Use the new HONOR_... macros.
+ * jump.c (reversed_comparison_code_parts): After searching for
+ the true comparison mode, use HONOR_NANS to decide whether it
+ can be safely reversed.
+ (reverse_condition_maybe_unordered): Remove IEEE check.
+ * simplify-rtx.c (simplify_binary_operation): Use the new macros
+ to decide which simplifications are valid. Allow the following
+ simplifications for IEEE: (-a + b) to (b - a), (a + -b) to (a - b),
+ and (a - -b) to (a + b).
+ (simplify_relational_operation): Use HONOR_NANS.
+ * doc/tm.texi: Document the MODE_HAS_... macros.
+
2002-03-07 Richard Earnshaw <rearnsha@arm.com>
* combine.c (simplify_comparison): If simplifying a logical shift
diff --git a/gcc/builtins.c b/gcc/builtins.c
index e3adb05feeb..c4aebd3a801 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1470,6 +1470,7 @@ expand_builtin_mathfn (exp, target, subtarget)
rtx op0, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
+ enum machine_mode argmode;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return 0;
@@ -1518,8 +1519,8 @@ expand_builtin_mathfn (exp, target, subtarget)
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
- target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
- builtin_optab, op0, target, 0);
+ argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
+ target = expand_unop (argmode, builtin_optab, op0, target, 0);
/* If we were unable to expand via the builtin, stop the
sequence (without outputting the insns) and return 0, causing
@@ -1530,18 +1531,12 @@ expand_builtin_mathfn (exp, target, subtarget)
return 0;
}
- /* If errno must be maintained and if we are not allowing unsafe
- math optimizations, check the result. */
+ /* If errno must be maintained, we must set it to EDOM for NaN results. */
- if (flag_errno_math && ! flag_unsafe_math_optimizations)
+ if (flag_errno_math && HONOR_NANS (argmode))
{
rtx lab1;
- /* Don't define the builtin FP instructions
- if your machine is not IEEE. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- abort ();
-
lab1 = gen_label_rtx ();
/* Test the result; if it is NaN, set errno=EDOM because
diff --git a/gcc/c-common.c b/gcc/c-common.c
index ed67bb05b91..7fad4b304f2 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -2202,10 +2202,15 @@ truthvalue_conversion (expr)
break;
case MINUS_EXPR:
- /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
- this case. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+ /* Perhaps reduce (x - y) != 0 to (x != y). The expressions
+ aren't guaranteed to the be same for modes that can represent
+ infinity, since if x and y are both +infinity, or both
+ -infinity, then x - y is not a number.
+
+ Note that this transformation is safe when x or y is NaN.
+ (x - y) is then NaN, and both (x - y) != 0 and x != y will
+ be false. */
+ if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0)))))
break;
/* fall through... */
case BIT_XOR_EXPR:
@@ -3051,6 +3056,81 @@ strip_array_types (type)
return type;
}
+static tree expand_unordered_cmp PARAMS ((tree, tree, enum tree_code,
+ enum tree_code));
+
+/* Expand a call to an unordered comparison function such as
+ __builtin_isgreater(). FUNCTION is the function's declaration and
+ PARAMS a list of the values passed. For __builtin_isunordered(),
+ UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR. In
+ other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes
+ that give the opposite of the desired result. UNORDERED_CODE is
+ used for modes that can hold NaNs and ORDERED_CODE is used for the
+ rest. */
+
+static tree
+expand_unordered_cmp (function, params, unordered_code, ordered_code)
+ tree function, params;
+ enum tree_code unordered_code, ordered_code;
+{
+ tree arg0, arg1, type;
+ enum tree_code code0, code1;
+
+ /* Check that we have exactly two arguments. */
+ if (params == 0 || TREE_CHAIN (params) == 0)
+ {
+ error ("too few arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (function)));
+ return error_mark_node;
+ }
+ else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
+ {
+ error ("too many arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (function)));
+ return error_mark_node;
+ }
+
+ arg0 = TREE_VALUE (params);
+ arg1 = TREE_VALUE (TREE_CHAIN (params));
+
+ code0 = TREE_CODE (TREE_TYPE (arg0));
+ code1 = TREE_CODE (TREE_TYPE (arg1));
+
+ /* Make sure that the arguments have a common type of REAL. */
+ type = 0;
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+
+ if (type == 0 || TREE_CODE (type) != REAL_TYPE)
+ {
+ error ("non-floating-point argument to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (function)));
+ return error_mark_node;
+ }
+
+ if (unordered_code == UNORDERED_EXPR)
+ {
+ if (MODE_HAS_NANS (TYPE_MODE (type)))
+ return build_binary_op (unordered_code,
+ convert (type, arg0),
+ convert (type, arg1),
+ 0);
+ else
+ return integer_zero_node;
+ }
+
+ return build_unary_op (TRUTH_NOT_EXPR,
+ build_binary_op (MODE_HAS_NANS (TYPE_MODE (type))
+ ? unordered_code
+ : ordered_code,
+ convert (type, arg0),
+ convert (type, arg1),
+ 0),
+ 0);
+}
+
+
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
to do something useful. */
@@ -3063,8 +3143,6 @@ tree
expand_tree_builtin (function, params, coerced_params)
tree function, params, coerced_params;
{
- enum tree_code code;
-
if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
return NULL_TREE;
@@ -3103,72 +3181,22 @@ expand_tree_builtin (function, params, coerced_params)
return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
case BUILT_IN_ISGREATER:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNLE_EXPR;
- else
- code = LE_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
case BUILT_IN_ISGREATEREQUAL:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNLT_EXPR;
- else
- code = LT_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
case BUILT_IN_ISLESS:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNGE_EXPR;
- else
- code = GE_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
case BUILT_IN_ISLESSEQUAL:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNGT_EXPR;
- else
- code = GT_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
case BUILT_IN_ISLESSGREATER:
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
- code = UNEQ_EXPR;
- else
- code = EQ_EXPR;
- goto unordered_cmp;
+ return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
case BUILT_IN_ISUNORDERED:
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- return integer_zero_node;
- code = UNORDERED_EXPR;
- goto unordered_cmp;
-
- unordered_cmp:
- {
- tree arg0, arg1;
-
- if (params == 0
- || TREE_CHAIN (params) == 0)
- {
- error ("too few arguments to function `%s'",
- IDENTIFIER_POINTER (DECL_NAME (function)));
- return error_mark_node;
- }
- else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
- {
- error ("too many arguments to function `%s'",
- IDENTIFIER_POINTER (DECL_NAME (function)));
- return error_mark_node;
- }
-
- arg0 = TREE_VALUE (params);
- arg1 = TREE_VALUE (TREE_CHAIN (params));
- arg0 = build_binary_op (code, arg0, arg1, 0);
- if (code != UNORDERED_EXPR)
- arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0);
- return arg0;
- }
- break;
+ return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
default:
break;
diff --git a/gcc/combine.c b/gcc/combine.c
index a155555c5fc..c9a67033dc8 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3978,12 +3978,14 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
if (GET_CODE (XEXP (x, 0)) == NOT)
return plus_constant (XEXP (XEXP (x, 0), 0), 1);
- /* (neg (minus X Y)) can become (minus Y X). */
+ /* (neg (minus X Y)) can become (minus Y X). This transformation
+ isn't safe for modes with signed zeros, since if X and Y are
+ both +0, (minus Y X) is the same as (minus X Y). If the rounding
+ mode is towards +infinity (or -infinity) then the two expressions
+ will be rounded differently. */
if (GET_CODE (XEXP (x, 0)) == MINUS
- && (! FLOAT_MODE_P (mode)
- /* x-y != -(y-x) with IEEE floating point. */
- || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations))
+ && !HONOR_SIGNED_ZEROS (mode)
+ && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
XEXP (XEXP (x, 0), 0));
@@ -4145,10 +4147,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
if (XEXP (x, 1) == const0_rtx)
return XEXP (x, 0);
- /* In IEEE floating point, x-0 is not the same as x. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
- || flag_unsafe_math_optimizations)
+ /* x - 0 is the same as x unless x's mode has signed zeros and
+ allows rounding towards -infinity. Under those conditions,
+ 0 - 0 is -0. */
+ if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
+ && HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
&& XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
return XEXP (x, 0);
break;
diff --git a/gcc/cse.c b/gcc/cse.c
index 7a05dad0307..1fe4752d8a0 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -3981,19 +3981,18 @@ fold_rtx (x, insn)
& HASH_MASK), mode_arg0))
&& p0->first_same_value == p1->first_same_value))
{
- /* Sadly two equal NaNs are not equivalent. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode_arg0)
- || flag_unsafe_math_optimizations)
- return ((code == EQ || code == LE || code == GE
- || code == LEU || code == GEU || code == UNEQ
- || code == UNLE || code == UNGE || code == ORDERED)
- ? true_rtx : false_rtx);
- /* Take care for the FP compares we can resolve. */
- if (code == UNEQ || code == UNLE || code == UNGE)
- return true_rtx;
- if (code == LTGT || code == LT || code == GT)
- return false_rtx;
+ /* Sadly two equal NaNs are not equivalent. */
+ if (!HONOR_NANS (mode_arg0))
+ return ((code == EQ || code == LE || code == GE
+ || code == LEU || code == GEU || code == UNEQ
+ || code == UNLE || code == UNGE
+ || code == ORDERED)
+ ? true_rtx : false_rtx);
+ /* Take care for the FP compares we can resolve. */
+ if (code == UNEQ || code == UNLE || code == UNGE)
+ return true_rtx;
+ if (code == LTGT || code == LT || code == GT)
+ return false_rtx;
}
/* If FOLDED_ARG0 is a register, see if the comparison we are
diff --git a/gcc/defaults.h b/gcc/defaults.h
index fe467404a68..5142ee7b471 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -465,4 +465,24 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
#define MODE_BASE_REG_CLASS(MODE) BASE_REG_CLASS
#endif
+#ifndef MODE_HAS_NANS
+#define MODE_HAS_NANS(MODE) \
+ (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+#endif
+
+#ifndef MODE_HAS_INFINITIES
+#define MODE_HAS_INFINITIES(MODE) \
+ (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+#endif
+
+#ifndef MODE_HAS_SIGNED_ZEROS
+#define MODE_HAS_SIGNED_ZEROS(MODE) \
+ (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+#endif
+
+#ifndef MODE_HAS_SIGN_DEPENDENT_ROUNDING
+#define MODE_HAS_SIGN_DEPENDENT_ROUNDING(MODE) \
+ (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+#endif
+
#endif /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 8d1a3188074..344c711f57c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1336,6 +1336,55 @@ defined for them.
The ordering of the component words of floating point values stored in
memory is controlled by @code{FLOAT_WORDS_BIG_ENDIAN}.
+@findex MODE_HAS_NANS
+@item MODE_HAS_NANS (@var{mode})
+When defined, this macro should be true if @var{mode} has a NaN
+representation. The compiler assumes that NaNs are not equal to
+anything (including themselves) and that addition, subtraction,
+multiplication and division all return NaNs when one operand is
+NaN@.
+
+By default, this macro is true if @var{mode} is a floating-point
+mode and the target floating-point format is IEEE@.
+
+@findex MODE_HAS_INFINITIES
+@item MODE_HAS_INFINITIES (@var{mode})
+This macro should be true if @var{mode} can represent infinity. At
+present, the compiler uses this macro to decide whether @samp{x - x}
+is always defined. By default, the macro is true when @var{mode}
+is a floating-point mode and the target format is IEEE@.
+
+@findex MODE_HAS_SIGNED_ZEROS
+@item MODE_HAS_SIGNED_ZEROS (@var{mode})
+True if @var{mode} distinguishes between positive and negative zero.
+The rules are expected to follow the IEEE standard:
+
+@itemize @bullet
+@item
+@samp{x + x} has the same sign as @samp{x}.
+
+@item
+If the sum of two values with opposite sign is zero, the result is
+positive for all rounding modes expect towards @minus{}infinity, for
+which it is negative.
+
+@item
+The sign of a product or quotient is negative when exactly one
+of the operands is negative.
+@end itemize
+
+The default definition is true if @var{mode} is a floating-point
+mode and the target format is IEEE@.
+
+@findex MODE_HAS_SIGN_DEPENDENT_ROUNDING
+@item MODE_HAS_SIGN_DEPENDENT_ROUNDING (@var{mode})
+If defined, this macro should be true for @var{mode} if it has at
+least one rounding mode in which @samp{x} and @samp{-x} can be
+rounded to numbers of different magnitude. Two such modes are
+towards @minus{}infinity and towards +infinity.
+
+The default definition of this macro is true if @var{mode} is
+a floating-point mode and the target format is IEEE@.
@end table
@deftypefn {Target Hook} bool TARGET_MS_BITFIELD_LAYOUT_P (tree @var{record_type})
diff --git a/gcc/flags.h b/gcc/flags.h
index 2c69497fb7d..3b0ee2fc947 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -633,4 +633,27 @@ extern int flag_non_call_exceptions;
/* Nonzero means put zero initialized data in the bss section. */
extern int flag_zero_initialized_in_bss;
+/* True if the given mode has a NaN representation and the treatment of
+ NaN operands is important. Certain optimizations, such as folding
+ x * 0 into x, are not correct for NaN operands, and are normally
+ disabled for modes with NaNs. The user can ask for them to be
+ done anyway using the -funsafe-math-optimizations switch. */
+#define HONOR_NANS(MODE) \
+ (MODE_HAS_NANS (MODE) && !flag_unsafe_math_optimizations)
+
+/* As for HONOR_NANS, but true if the mode can represent infinity and
+ the treatment of infinite values is important. */
+#define HONOR_INFINITIES(MODE) \
+ (MODE_HAS_INFINITIES (MODE) && !flag_unsafe_math_optimizations)
+
+/* Like HONOR_NANS, but true if the given mode distinguishes between
+ postive and negative zero, and the sign of zero is important. */
+#define HONOR_SIGNED_ZEROS(MODE) \
+ (MODE_HAS_SIGNED_ZEROS (MODE) && !flag_unsafe_math_optimizations)
+
+/* Like HONOR_NANS, but true if given mode supports sign-dependent rounding,
+ and the rounding mode is important. */
+#define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \
+ (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && !flag_unsafe_math_optimizations)
+
#endif /* ! GCC_FLAGS_H */
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index aee10565e9a..feb3e5f72fd 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -105,6 +105,7 @@ static tree constant_boolean_node PARAMS ((int, tree));
static int count_cond PARAMS ((tree, int));
static tree fold_binary_op_with_conditional_arg
PARAMS ((enum tree_code, tree, tree, tree, int));
+static bool fold_real_zero_addition_p PARAMS ((tree, tree, int));
#ifndef BRANCH_COST
#define BRANCH_COST 1
@@ -4372,6 +4373,43 @@ fold_binary_op_with_conditional_arg (code, type, cond, arg, cond_first_p)
}
+/* Subroutine of fold() that checks for the addition of +/- 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.
+
+ X + 0 and X - 0 both give X when X is NaN, infinite, or non-zero
+ and finite. The problematic cases are when X is zero, and its mode
+ has signed zeros. In the case of rounding towards -infinity,
+ X - 0 is not the same as X because 0 - 0 is -0. In other rounding
+ modes, X + 0 is not the same as X because -0 + 0 is 0. */
+
+static bool
+fold_real_zero_addition_p (type, addend, negate)
+ tree type, addend;
+ int negate;
+{
+ if (!real_zerop (addend))
+ return false;
+
+ /* Allow the fold if zeros aren't signed, or their sign isn't important. */
+ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
+ return true;
+
+ /* Treat x + -0 as x - 0 and x - -0 as x + 0. */
+ if (TREE_CODE (addend) == REAL_CST
+ && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (addend)))
+ 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 unless rounding towards -infinity is
+ supported. */
+ return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type));
+}
+
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
@@ -5001,16 +5039,15 @@ fold (expr)
same));
}
}
- /* In IEEE floating point, x+0 may not equal x. */
- else if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations)
- && real_zerop (arg1))
- return non_lvalue (convert (type, arg0));
- /* x+(-0) equals x, even for IEEE. */
- else if (TREE_CODE (arg1) == REAL_CST
- && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
+
+ /* See if ARG1 is zero and X + ARG1 reduces to X. */
+ else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
return non_lvalue (convert (type, arg0));
+ /* Likewise if the operands are reversed. */
+ else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+ return non_lvalue (convert (type, arg1));
+
bit_rotate:
/* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
is a rotate of A by C1 bits. */
@@ -5163,16 +5200,15 @@ fold (expr)
TREE_OPERAND (arg0, 1)));
}
- else if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations)
- {
- /* Except with IEEE floating point, 0-x equals -x. */
- if (! wins && real_zerop (arg0))
- return negate_expr (convert (type, arg1));
- /* Except with IEEE floating point, x-0 equals x. */
- if (real_zerop (arg1))
- return non_lvalue (convert (type, arg0));
- }
+ /* See if ARG1 is zero and X - ARG1 reduces to X. */
+ else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 1))
+ return non_lvalue (convert (type, arg0));
+
+ /* (ARG0 - ARG1) is the same as (-ARG1 + ARG0). So check whether
+ ARG0 is zero and X + ARG0 reduces to X, since that would mean
+ (-ARG1 + ARG0) reduces to -ARG1. */
+ else if (!wins && fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+ return negate_expr (convert (type, arg1));
/* Fold &x - &x. This can happen from &x.foo - &x.
This is unsafe for certain floats even in non-IEEE formats.
@@ -5217,9 +5253,12 @@ fold (expr)
}
else
{
- /* x*0 is 0, except for IEEE floating point. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations)
+ /* Maybe fold x * 0 to 0. The expressions aren't the same
+ when x is NaN, since x * 0 is also NaN. Nor are they the
+ same in modes with signed zeros, since multiplying a
+ negative value by 0 gives -0, not +0. */
+ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
+ && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
&& real_zerop (arg1))
return omit_one_operand (type, arg1, arg0);
/* In IEEE floating point, x*1 is not equivalent to x for snans.
@@ -6504,23 +6543,38 @@ fold (expr)
/* If we have A op B ? A : C, we may be able to convert this to a
simpler expression, depending on the operation and the values
- of B and C. IEEE floating point prevents this though,
- because A or B might be -0.0 or a NaN. */
+ of B and C. Signed zeros prevent all of these transformations,
+ for reasons given above each one. */
if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
- && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))
- || flag_unsafe_math_optimizations)
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
- arg1, TREE_OPERAND (arg0, 1)))
+ arg1, TREE_OPERAND (arg0, 1))
+ && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
{
tree arg2 = TREE_OPERAND (t, 2);
enum tree_code comp_code = TREE_CODE (arg0);
STRIP_NOPS (arg2);
- /* If we have A op 0 ? A : -A, this is A, -A, abs (A), or -abs (A),
- depending on the comparison operation. */
+ /* If we have A op 0 ? A : -A, consider applying the following
+ transformations:
+
+ A == 0? A : -A same as -A
+ A != 0? A : -A same as A
+ A >= 0? A : -A same as abs (A)
+ A > 0? A : -A same as abs (A)
+ A <= 0? A : -A same as -abs (A)
+ A < 0? A : -A same as -abs (A)
+
+ None of these transformations work for modes with signed
+ zeros. If A is +/-0, the first two transformations will
+ change the sign of the result (from +0 to -0, or vice
+ versa). The last four will fix the sign of the result,
+ even though the original expressions could be positive or
+ negative, depending on the sign of A.
+
+ Note that all these transformations are correct if A is
+ NaN, since the two alternatives (A and -A) are also NaNs. */
if ((FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 1)))
? real_zerop (TREE_OPERAND (arg0, 1))
: integer_zerop (TREE_OPERAND (arg0, 1)))
@@ -6535,7 +6589,6 @@ fold (expr)
negate_expr
(convert (TREE_TYPE (TREE_OPERAND (t, 1)),
arg1))));
-
case NE_EXPR:
return pedantic_non_lvalue (convert (type, arg1));
case GE_EXPR:
@@ -6558,8 +6611,10 @@ fold (expr)
abort ();
}
- /* If this is A != 0 ? A : 0, this is simply A. For ==, it is
- always zero. */
+ /* A != 0 ? A : 0 is simply A, unless A is -0. Likewise
+ A == 0 ? A : 0 is always 0 unless A is -0. Note that
+ both transformations are correct when A is NaN: A != 0
+ is then true, and A == 0 is false. */
if (integer_zerop (TREE_OPERAND (arg0, 1)) && integer_zerop (arg2))
{
@@ -6569,9 +6624,32 @@ fold (expr)
return pedantic_non_lvalue (convert (type, integer_zero_node));
}
- /* If this is A op B ? A : B, this is either A, B, min (A, B),
- or max (A, B), depending on the operation. */
-
+ /* Try some transformations of A op B ? A : B.
+
+ A == B? A : B same as B
+ A != B? A : B same as A
+ A >= B? A : B same as max (A, B)
+ A > B? A : B same as max (B, A)
+ A <= B? A : B same as min (A, B)
+ A < B? A : B same as min (B, A)
+
+ As above, these transformations don't work in the presence
+ of signed zeros. For example, if A and B are zeros of
+ opposite sign, the first two transformations will change
+ the sign of the result. In the last four, the original
+ expressions give different results for (A=+0, B=-0) and
+ (A=-0, B=+0), but the transformed expressions do not.
+
+ The first two transformations are correct if either A or B
+ is a NaN. In the first transformation, the condition will
+ be false, and B will indeed be chosen. In the case of the
+ second transformation, the condition A != B will be true,
+ and A will be chosen.
+
+ The conversions to max() and min() are not correct if B is
+ a number and A is not. The conditions in the original
+ expressions will be false, so all four give B. The min()
+ and max() versions would give a NaN instead. */
if (operand_equal_for_comparison_p (TREE_OPERAND (arg0, 1),
arg2, TREE_OPERAND (arg0, 0)))
{
@@ -6595,21 +6673,23 @@ fold (expr)
operand which will be used if they are equal first
so that we can convert this back to the
corresponding COND_EXPR. */
- return pedantic_non_lvalue
- (convert (type, fold (build (MIN_EXPR, comp_type,
- (comp_code == LE_EXPR
- ? comp_op0 : comp_op1),
- (comp_code == LE_EXPR
- ? comp_op1 : comp_op0)))));
+ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
+ return pedantic_non_lvalue
+ (convert (type, fold (build (MIN_EXPR, comp_type,
+ (comp_code == LE_EXPR
+ ? comp_op0 : comp_op1),
+ (comp_code == LE_EXPR
+ ? comp_op1 : comp_op0)))));
break;
case GE_EXPR:
case GT_EXPR:
- return pedantic_non_lvalue
- (convert (type, fold (build (MAX_EXPR, comp_type,
- (comp_code == GE_EXPR
- ? comp_op0 : comp_op1),
- (comp_code == GE_EXPR
- ? comp_op1 : comp_op0)))));
+ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
+ return pedantic_non_lvalue
+ (convert (type, fold (build (MAX_EXPR, comp_type,
+ (comp_code == GE_EXPR
+ ? comp_op0 : comp_op1),
+ (comp_code == GE_EXPR
+ ? comp_op1 : comp_op0)))));
break;
default:
abort ();
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 038b8c5d5ff..7a450bc97a9 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -1295,12 +1295,11 @@ noce_try_minmax (if_info)
if (no_new_pseudos)
return FALSE;
- /* ??? Reject FP modes since we don't know how 0 vs -0 or NaNs
- will be resolved with an SMIN/SMAX. It wouldn't be too hard
+ /* ??? Reject modes with NaNs or signed zeros since we don't know how
+ they will be resolved with an SMIN/SMAX. It wouldn't be too hard
to get the target to tell us... */
- if (FLOAT_MODE_P (GET_MODE (if_info->x))
- && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && ! flag_unsafe_math_optimizations)
+ if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))
+ || HONOR_NANS (GET_MODE (if_info->x)))
return FALSE;
cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
diff --git a/gcc/jump.c b/gcc/jump.c
index 7d01a55f3ba..86b3a942769 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -704,11 +704,6 @@ reversed_comparison_code_parts (code, arg0, arg1, insn)
break;
}
- /* In case we give up IEEE compatibility, all comparisons are reversible. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations)
- return reverse_condition (code);
-
if (GET_MODE_CLASS (mode) == MODE_CC
#ifdef HAVE_cc0
|| arg0 == cc0_rtx
@@ -757,11 +752,12 @@ reversed_comparison_code_parts (code, arg0, arg1, insn)
}
}
- /* An integer condition. */
+ /* Test for an integer condition, or a floating-point comparison
+ in which NaNs can be ignored. */
if (GET_CODE (arg0) == CONST_INT
|| (GET_MODE (arg0) != VOIDmode
&& GET_MODE_CLASS (mode) != MODE_CC
- && ! FLOAT_MODE_P (mode)))
+ && !HONOR_NANS (mode)))
return reverse_condition (code);
return UNKNOWN;
@@ -840,10 +836,6 @@ enum rtx_code
reverse_condition_maybe_unordered (code)
enum rtx_code code;
{
- /* Non-IEEE formats don't have unordered conditions. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- return reverse_condition (code);
-
switch (code)
{
case EQ:
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index b50a3392f7b..88ca32b5b24 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -981,16 +981,15 @@ simplify_binary_operation (code, mode, op0, op1)
switch (code)
{
case PLUS:
- /* In IEEE floating point, x+0 is not the same as x. Similarly
- for the other optimizations below. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && FLOAT_MODE_P (mode) && ! flag_unsafe_math_optimizations)
- break;
-
- if (trueop1 == CONST0_RTX (mode))
+ /* Maybe simplify x + 0 to x. The two expressions are equivalent
+ when x is NaN, infinite, or finite and non-zero. They aren't
+ when x is -0 and the rounding mode is not towards -infinity,
+ since (-0) + 0 is then 0. */
+ if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
return op0;
- /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
+ /* ((-a) + b) -> (b - a) and similarly for (a + (-b)). These
+ transformations are safe even for IEEE. */
if (GET_CODE (op0) == NEG)
return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
else if (GET_CODE (op1) == NEG)
@@ -1122,12 +1121,6 @@ simplify_binary_operation (code, mode, op0, op1)
break;
case MINUS:
- /* None of these optimizations can be done for IEEE
- floating point. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && FLOAT_MODE_P (mode) && ! flag_unsafe_math_optimizations)
- break;
-
/* We can't assume x-x is 0 even with non-IEEE floating point,
but since it is zero except in very strange circumstances, we
will treat it as zero with -funsafe-math-optimizations. */
@@ -1136,16 +1129,23 @@ simplify_binary_operation (code, mode, op0, op1)
&& (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
return CONST0_RTX (mode);
- /* Change subtraction from zero into negation. */
- if (trueop0 == CONST0_RTX (mode))
+ /* Change subtraction from zero into negation. (0 - x) is the
+ same as -x when x is NaN, infinite, or finite and non-zero.
+ But if the mode has signed zeros, and does not round towards
+ -infinity, then 0 - 0 is 0, not -0. */
+ if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
return gen_rtx_NEG (mode, op1);
/* (-1 - a) is ~a. */
if (trueop0 == constm1_rtx)
return gen_rtx_NOT (mode, op1);
- /* Subtracting 0 has no effect. */
- if (trueop1 == CONST0_RTX (mode))
+ /* Subtracting 0 has no effect unless the mode has signed zeros
+ and supports rounding towards -infinity. In such a case,
+ 0 - 0 is -0. */
+ if (!(HONOR_SIGNED_ZEROS (mode)
+ && HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+ && trueop1 == CONST0_RTX (mode))
return op0;
/* See if this is something like X * C - X or vice versa or
@@ -1202,7 +1202,7 @@ simplify_binary_operation (code, mode, op0, op1)
}
}
- /* (a - (-b)) -> (a + b). */
+ /* (a - (-b)) -> (a + b). True even for IEEE. */
if (GET_CODE (op1) == NEG)
return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
@@ -1248,9 +1248,12 @@ simplify_binary_operation (code, mode, op0, op1)
return tem ? tem : gen_rtx_NEG (mode, op0);
}
- /* In IEEE floating point, x*0 is not always 0. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+ /* Maybe simplify x * 0 to 0. The reduction is not valid if
+ x is NaN, since x * 0 is then also NaN. Nor is it valid
+ when the mode has signed zeros, since multiplying a negative
+ number by 0 will give -0, not 0. */
+ if (!HONOR_NANS (mode)
+ && !HONOR_SIGNED_ZEROS (mode)
&& trueop1 == CONST0_RTX (mode)
&& ! side_effects_p (op0))
return op1;
@@ -1361,9 +1364,12 @@ simplify_binary_operation (code, mode, op0, op1)
return op0;
}
- /* In IEEE floating point, 0/x is not always 0. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+ /* Maybe change 0 / x to 0. This transformation isn't safe for
+ modes with NaNs, since 0 / 0 will then be NaN rather than 0.
+ Nor is it safe for modes with signed zeros, since dividing
+ 0 by a negative number gives -0, not 0. */
+ if (!HONOR_NANS (mode)
+ && !HONOR_SIGNED_ZEROS (mode)
&& trueop0 == CONST0_RTX (mode)
&& ! side_effects_p (op1))
return op0;
@@ -2018,12 +2024,9 @@ simplify_relational_operation (code, mode, op0, op1)
if (flag_unsafe_math_optimizations && code == UNORDERED)
return const0_rtx;
- /* For non-IEEE floating-point, if the two operands are equal, we know the
+ /* For modes without NaNs, if the two operands are equal, we know the
result. */
- if (rtx_equal_p (trueop0, trueop1)
- && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (GET_MODE (trueop0))
- || flag_unsafe_math_optimizations))
+ if (!HONOR_NANS (GET_MODE (trueop0)) && rtx_equal_p (trueop0, trueop1))
equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
/* If the operands are floating-point constants, see if we can fold