[Committed] Correct conditions to perform -(X-Y) -> Y-X
Roger Sayle
roger@eyesopen.com
Mon Nov 13 03:30:00 GMT 2006
As recently pointed out by Revital Eres on the gcc list, we're currently
inconsistent between fold-const and simplify-rtx about when we can
simplify -(X-Y) to Y-X. The issue is that fold still uses the historical
flag_unsafe_math_optimizations, where as simplify-rtx uses the newer and
more precise HONOR_SIGNED_ZEROS and HONOR_SIGN_DEPENDENT_ROUNDING macros.
Under the surface, HONOR_SIGNED_ZEROS actually just tests for
flag_unsafe_math_optimizations, and the command line "-ffast-math"
simultaneouly turns off both conditions.
The reason why HONOR_SIGNED_ZERO is significant for this transformation
is because "-0.0 - -0.0" is "+0.0" which when negated is "-0.0", but
clearly this isn't the same as "-0.0 - -0.0". IEEE, got to love them.
The reason why HONOR_SIGN_DEPENDENT_ROUNDING is significant is that
although both -(X-Y) and Y-X only each have one rounding operation,
the sign of the value being rounded is different. Hence in non-default
rounding modes, such as round to +Inf or round to -Inf, the results
may differ in the least significant bit.
The discrepancy between the tree-ssa and RTL optimizers is extremely
rare, both don't perform the operation by default, and do with
-ffast-math. The only discrepancy is with the (conflicting?) options
-funsafe-math-optimizations and -frounding-math.
The following patch has been tested on x86_64-unknown-linux-gnu, with
a full "make bootstrap", all default languages including Ada, and
regression tested with a top-level "make -k check" with no new failures.
Committed to mainline as revision 118744.
2006-11-12 Roger Sayle <roger@eyesopen.com>
* fold-const.c (negate_expr_p) <PLUS_EXPR, MINUS_EXPR>: Correct/refine
condition for transformations. Use !HONOR_SIGN_DEPENDENT_ROUNDING
&& !HONOR_SIGNED_ZEROS instead of flag_unsafe_math_optimizations.
(fold_negate_expr) <PLUS_EXPR, MINUS_EXPR>: Likewise.
Index: fold-const.c
===================================================================
*** fold-const.c (revision 118694)
--- fold-const.c (working copy)
*************** negate_expr_p (tree t)
*** 971,977 ****
&& negate_expr_p (TREE_IMAGPART (t));
case PLUS_EXPR:
! if (FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations)
return false;
/* -(A + B) -> (-B) - A. */
if (negate_expr_p (TREE_OPERAND (t, 1))
--- 971,978 ----
&& negate_expr_p (TREE_IMAGPART (t));
case PLUS_EXPR:
! if (HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type))
! || HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
return false;
/* -(A + B) -> (-B) - A. */
if (negate_expr_p (TREE_OPERAND (t, 1))
*************** negate_expr_p (tree t)
*** 983,989 ****
case MINUS_EXPR:
/* We can't turn -(A-B) into B-A when we honor signed zeros. */
! return (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
&& reorder_operands_p (TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1));
--- 984,991 ----
case MINUS_EXPR:
/* We can't turn -(A-B) into B-A when we honor signed zeros. */
! return !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type))
! && !HONOR_SIGNED_ZEROS (TYPE_MODE (type))
&& reorder_operands_p (TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1));
*************** fold_negate_expr (tree t)
*** 1095,1101 ****
return TREE_OPERAND (t, 0);
case PLUS_EXPR:
! if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
{
/* -(A + B) -> (-B) - A. */
if (negate_expr_p (TREE_OPERAND (t, 1))
--- 1097,1104 ----
return TREE_OPERAND (t, 0);
case PLUS_EXPR:
! if (!HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type))
! && !HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
{
/* -(A + B) -> (-B) - A. */
if (negate_expr_p (TREE_OPERAND (t, 1))
*************** fold_negate_expr (tree t)
*** 1119,1125 ****
case MINUS_EXPR:
/* - (A - B) -> B - A */
! if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
&& reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
return fold_build2 (MINUS_EXPR, type,
TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
--- 1122,1129 ----
case MINUS_EXPR:
/* - (A - B) -> B - A */
! if (!HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type))
! && !HONOR_SIGNED_ZEROS (TYPE_MODE (type))
&& reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
return fold_build2 (MINUS_EXPR, type,
TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
Roger
--
More information about the Gcc-patches
mailing list