PR tree-optimization/96392 Optimize x+0.0 if x is an integer

Message ID 024401d75e31$10edfe40$32c9fac0$@nextmovesoftware.com
State New
Headers show
Series
  • PR tree-optimization/96392 Optimize x+0.0 if x is an integer
Related show

Commit Message

Roger Sayle June 10, 2021, 7:44 p.m.
The patch implements a missed optimization enhancement.  Under usual
IEEE rules, x+0.0 can't be simplified to x when x might potentially
be an IEEE minus zero (-0.0).  The current logic in the middle-end
checks whether the type of x should honor signed zeros, but with this
patch we introduce tree_expr_maybe_real_minus_zero_p that allows us
to confirm that the value can't possibly be -0.0, for example, the result
of a conversion from an integer type, or the result of fabs (or has a
type that doesn't honor signed zero).

Whilst modifying match.pd, I also converted some additional folding
transformations from "testing the type" to "testing the value".

The following patch has been tested on x86_64-pc-linux-gnu with
a make bootstrap and make -k check with no new failures.

Ok for mainline?


2020-06-10  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
	PR tree-optimization/96392
	* fold-const.c (fold_real_zero_addition_p): Take both arguments
	of the addition or subtraction, not just the zero.  Use this
	other argument in tests for signaling NaNs and signed zeros.
	(tree_expr_maybe_real_minus_zero_p): New predicate.
	* fold-const.h (fold_real_zero_addition_p): Update prototype.
	(tree_expr_maybe_real_minus_zero_p): New function prototype.
	* match.pd: Update calls to fold_real_zero_addition_p.
	Replace HONOR_NANS with tree_expr_maybe_nan_p.
	Replace HONOR_SIGNED_ZEROS with tree_expr_maybe_real_minus_zero_p.
	Replace HONOR_SNANS with tree_expr_maybe_signaling_nan_p.
	* tree-ssa-reassoc.c (eliminate_using_constants): Update
	call to fold_real_zero_addition_p.

gcc/testsuite/ChangeLog
	PR tree-optimization/96392
	* gcc.dg/pr96392.c: New test.

Roger
--
Roger Sayle
NextMove Software
Cambridge, UK

/* PR tree-optimization/96392 */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */

double plus0(int x)
{
  return x + 0.0;
}

double sub0(int x)
{
  return x - 0.0;
}

double mult0(int x)
{
  return 0.0 * x;
}

double negate(int x)
{
  return 0.0 - x;
}

double subtract(int x)
{
  return (double)x - (double)x;
}

/* { dg-final { scan-tree-dump-not " \\+ " "optimized" } } */
/* { dg-final { scan-tree-dump-not " \\- " "optimized" } } */
/* { dg-final { scan-tree-dump-not " \\* " "optimized" } } */

Comments

Andreas Krebbel via Gcc-patches June 11, 2021, 11:54 a.m. | #1
On Thu, Jun 10, 2021 at 9:45 PM Roger Sayle <roger@nextmovesoftware.com> wrote:
>

>

> The patch implements a missed optimization enhancement.  Under usual

> IEEE rules, x+0.0 can't be simplified to x when x might potentially

> be an IEEE minus zero (-0.0).  The current logic in the middle-end

> checks whether the type of x should honor signed zeros, but with this

> patch we introduce tree_expr_maybe_real_minus_zero_p that allows us

> to confirm that the value can't possibly be -0.0, for example, the result

> of a conversion from an integer type, or the result of fabs (or has a

> type that doesn't honor signed zero).

>

> Whilst modifying match.pd, I also converted some additional folding

> transformations from "testing the type" to "testing the value".

>

> The following patch has been tested on x86_64-pc-linux-gnu with

> a make bootstrap and make -k check with no new failures.

>

> Ok for mainline?


OK.  Maybe we can at some point record & propagate these
FP value predicates on SSA names just similar to SSA_NAME_RANGE_INFO ...

Thanks,
Richard.

>

> 2020-06-10  Roger Sayle  <roger@nextmovesoftware.com>

>

> gcc/ChangeLog

>         PR tree-optimization/96392

>         * fold-const.c (fold_real_zero_addition_p): Take both arguments

>         of the addition or subtraction, not just the zero.  Use this

>         other argument in tests for signaling NaNs and signed zeros.

>         (tree_expr_maybe_real_minus_zero_p): New predicate.

>         * fold-const.h (fold_real_zero_addition_p): Update prototype.

>         (tree_expr_maybe_real_minus_zero_p): New function prototype.

>         * match.pd: Update calls to fold_real_zero_addition_p.

>         Replace HONOR_NANS with tree_expr_maybe_nan_p.

>         Replace HONOR_SIGNED_ZEROS with tree_expr_maybe_real_minus_zero_p.

>         Replace HONOR_SNANS with tree_expr_maybe_signaling_nan_p.

>         * tree-ssa-reassoc.c (eliminate_using_constants): Update

>         call to fold_real_zero_addition_p.

>

> gcc/testsuite/ChangeLog

>         PR tree-optimization/96392

>         * gcc.dg/pr96392.c: New test.

>

> Roger

> --

> Roger Sayle

> NextMove Software

> Cambridge, UK

>
Andreas Krebbel via Gcc-patches June 13, 2021, 9:39 p.m. | #2
On 6/11/2021 5:54 AM, Richard Biener via Gcc-patches wrote:
> On Thu, Jun 10, 2021 at 9:45 PM Roger Sayle <roger@nextmovesoftware.com> wrote:

>>

>> The patch implements a missed optimization enhancement.  Under usual

>> IEEE rules, x+0.0 can't be simplified to x when x might potentially

>> be an IEEE minus zero (-0.0).  The current logic in the middle-end

>> checks whether the type of x should honor signed zeros, but with this

>> patch we introduce tree_expr_maybe_real_minus_zero_p that allows us

>> to confirm that the value can't possibly be -0.0, for example, the result

>> of a conversion from an integer type, or the result of fabs (or has a

>> type that doesn't honor signed zero).

>>

>> Whilst modifying match.pd, I also converted some additional folding

>> transformations from "testing the type" to "testing the value".

>>

>> The following patch has been tested on x86_64-pc-linux-gnu with

>> a make bootstrap and make -k check with no new failures.

>>

>> Ok for mainline?

> OK.  Maybe we can at some point record & propagate these

> FP value predicates on SSA names just similar to SSA_NAME_RANGE_INFO ...

That's certainly been the hope.  My vision was to have Ranger tackle 
tracking the special values in the FP space.  But I think Aldy and 
Andrew are primarily focused on getting Ranger to the point where it 
subsumes [E]VRP at the moment.

Jeff

Patch

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 6e5835a..95673d2 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -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
 
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 2a74287..0d8d786 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -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 *);
diff --git a/gcc/match.pd b/gcc/match.pd
index d06ff17..b5ed87f 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -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.  */
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 6dfc703..2dd4435 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -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)