From 920d0fb5731b8a6a4888e16cbf5ecc792c0ae262 Mon Sep 17 00:00:00 2001 From: rsandifo Date: Thu, 7 Mar 2002 11:37:16 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@50401 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 30 +++++++++ gcc/builtins.c | 15 ++--- gcc/c-common.c | 152 +++++++++++++++++++++++++++------------------- gcc/combine.c | 21 ++++--- gcc/cse.c | 25 ++++---- gcc/defaults.h | 20 ++++++ gcc/doc/tm.texi | 49 +++++++++++++++ gcc/flags.h | 23 +++++++ gcc/fold-const.c | 174 ++++++++++++++++++++++++++++++++++++++--------------- gcc/ifcvt.c | 9 ++- gcc/jump.c | 14 +---- gcc/simplify-rtx.c | 63 ++++++++++--------- 12 files changed, 408 insertions(+), 187 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6def670..2940fce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2002-03-07 Richard Sandiford + + * 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 * combine.c (simplify_comparison): If simplifying a logical shift diff --git a/gcc/builtins.c b/gcc/builtins.c index e3adb05..c4aebd3 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 ed67bb0..7fad4b3 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 a155555..c9a6703 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 7a05dad..1fe4752 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 fe46740..5142ee7 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 8d1a318..344c711 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 2c69497..3b0ee2f 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 aee1056..feb3e5f 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 038b8c5..7a450bc9 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 7d01a55..86b3a94 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 b50a339..88ca32b 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 -- 2.7.4