On Tue, 7 May 2019, Jakub Jelinek wrote:

> Hi!
> 
> fold_real_zero_addition_p will fold x + (-0.0) or x - 0.0 to x
> when not -frounding-math, but not the rest of the options when
> -fsigned-zeros, and not when -fsignaling-nans.
> If we have (x + 0.0) + 0.0, we can fold that to just x + 0.0 even
> when honoring signed zeros, and IMNSHO even when honoring sNaNs,
> of course unless -frounding-math, then we can't do anything.
> For x other than 0.0, -0.0 and sNaN it is obviously correct, for sNaN
> sNaN + 0.0 will raise an exception and turn the result into qNaN, which
> will not raise further exception on the second addition, so IMHO it is ok
> too (unless we want to say special case -fnon-call-exceptions and the
> exception handler changing the result back to sNaN and expecting yet another
> exception).  For 0.0/-0.0 if we can assume rounding other than towards
> negative infinity, the results are:
>   x                         x
> (0.0 + 0.0) + 0.0 = 0.0 = (0.0 + 0.0)
> (-0.0 + 0.0) + 0.0 = 0.0 = (-0.0 + 0.0)
> (0.0 - 0.0) - 0.0 = 0.0 = (0.0 - 0.0)
> (-0.0 - 0.0) - 0.0 = -0.0 = (-0.0 - 0.0)
> (0.0 + 0.0) - 0.0 = 0.0 = (0.0 + 0.0)
> (-0.0 + 0.0) - 0.0 = 0.0 = (-0.0 + 0.0)
> For the above ones, the two operations are always equal to the inner operation
> (0.0 - 0.0) + 0.0 = 0.0 = 0.0 + 0.0
> (-0.0 - 0.0) + 0.0 = 0.0 = -0.0 + 0.0
> For the above cases, the two operations are always equal to the outer 
> operation
> 
> If it is y + (-0.0), it is equivalent to y - 0.0 and if it is y - (-0.0),
> it is equivalent to y + 0.0 in the above.
> 
> For rounding towards negative infinity, 0.0 - 0.0 is -0.0 rather than 0.0
> and so some of the above equivalencies are not true.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2019-05-07  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/90356
>       * match.pd ((X +/- 0.0) +/- 0.0): Optimize into X +/- 0.0 if possible.
> 
>       * gcc.dg/tree-ssa/pr90356-1.c: New test.
>       * gcc.dg/tree-ssa/pr90356-2.c: New test.
>       * gcc.dg/tree-ssa/pr90356-3.c: New test.
>       * gcc.dg/tree-ssa/pr90356-4.c: New test.
> 
> --- gcc/match.pd.jj   2019-05-03 15:22:07.370401908 +0200
> +++ gcc/match.pd      2019-05-06 11:26:04.701663020 +0200
> @@ -152,6 +152,28 @@ (define_operator_list COND_TERNARY
>   (if (fold_real_zero_addition_p (type, @1, 1))
>    (non_lvalue @0)))
>  
> +/* Even if the fold_real_zero_addition_p can't simplify X + 0.0
> +   into X, we can optimize (X + 0.0) + 0.0 or (X + 0.0) - 0.0
> +   or (X - 0.0) + 0.0 into X + 0.0 and (X - 0.0) - 0.0 into X - 0.0
> +   if not -frounding-math.  For sNaNs the first operation would raise
> +   exceptions but turn the result into qNan, so the second operation
> +   would not raise it.   */
> +(for inner_op (plus minus)
> + (for outer_op (plus minus)
> +  (simplify
> +   (outer_op (inner_op @0 real_zerop@1) real_zerop@2)
> +    (if (TREE_CODE (@1) == REAL_CST
> +      && TREE_CODE (@2) == REAL_CST

Will leave the "correctness check" for other folks but the above is
better written as

+   (outer_op (inner_op @0 REAL_CST@1) REAL_CST@2)
+    (if (real_zerop (@1)
+         && real_zerop (@2)

because that gets code-generated better.  Btw, for -fsignalling-nans
can we have a literal sNaN?  Then you need :c on the inner_op since
I'm not sure we canonicalize to sNaN + 0.0 rather than 0.0 + sNaN.
Maybe not worth optimizing though (since we rule out -frounding-math
a similar case there doesn't need to be considered).

> +      && HONOR_SIGNED_ZEROS (element_mode (type))
> +      && !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type)))

You can write HONOR_SIGNED_ZEROS (type) here for brevity.

> +     (with { bool plus1 = ((inner_op == PLUS_EXPR)
> +                        ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)));
> +          bool plus2 = ((outer_op == PLUS_EXPR)
> +                        ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@2))); }
> +      (if (plus2 && !plus1)
> +       (outer_op @0 @2)
> +       (inner_op @0 @1)))))))
> +
>  /* Simplify x - x.
>     This is unsafe for certain floats even in non-IEEE formats.
>     In IEEE, it is unsafe because it does wrong for NaNs.
> --- gcc/testsuite/gcc.dg/tree-ssa/pr90356-1.c.jj      2019-05-06 
> 11:39:58.998288472 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr90356-1.c 2019-05-06 11:42:53.597489688 
> +0200
> @@ -0,0 +1,23 @@
> +/* PR tree-optimization/90356 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-rounding-math -fsignaling-nans -fsigned-zeros 
> -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "x_\[0-9]*.D. \\+ 0.0;" 12 "optimized" 
> } } */
> +/* { dg-final { scan-tree-dump-times "y_\[0-9]*.D. - 0.0;" 4 "optimized" } } 
> */
> +/* { dg-final { scan-tree-dump-times " \[+-] 0.0;" 16 "optimized" } } */
> +
> +double f1 (double x) { return (x + 0.0) + 0.0; }
> +double f2 (double y) { return (y + (-0.0)) + (-0.0); }
> +double f3 (double y) { return (y - 0.0) - 0.0; }
> +double f4 (double x) { return (x - (-0.0)) - (-0.0); }
> +double f5 (double x) { return (x + 0.0) - 0.0; }
> +double f6 (double x) { return (x + (-0.0)) - (-0.0); }
> +double f7 (double x) { return (x - 0.0) + 0.0; }
> +double f8 (double x) { return (x - (-0.0)) + (-0.0); }
> +double f9 (double x) { double t = x + 0.0; return t + 0.0; }
> +double f10 (double y) { double t = y + (-0.0); return t + (-0.0); }
> +double f11 (double y) { double t = y - 0.0; return t - 0.0; }
> +double f12 (double x) { double t = x - (-0.0); return t - (-0.0); }
> +double f13 (double x) { double t = x + 0.0; return t - 0.0; }
> +double f14 (double x) { double t = x + (-0.0); return t - (-0.0); }
> +double f15 (double x) { double t = x - 0.0; return t + 0.0; }
> +double f16 (double x) { double t = x - (-0.0); return t + (-0.0); }
> --- gcc/testsuite/gcc.dg/tree-ssa/pr90356-2.c.jj      2019-05-06 
> 11:43:07.232271129 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr90356-2.c 2019-05-06 11:45:41.145803937 
> +0200
> @@ -0,0 +1,8 @@
> +/* PR tree-optimization/90356 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-rounding-math -fno-signaling-nans -fsigned-zeros 
> -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "x_\[0-9]*.D. \\+ 0.0;" 12 "optimized" 
> } } */
> +/* { dg-final { scan-tree-dump-times "y_\[0-9]*.D. - 0.0;" 0 "optimized" } } 
> */
> +/* { dg-final { scan-tree-dump-times " \[+-] 0.0;" 12 "optimized" } } */
> +
> +#include "pr90356-1.c"
> --- gcc/testsuite/gcc.dg/tree-ssa/pr90356-3.c.jj      2019-05-06 
> 11:45:05.056382441 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr90356-3.c 2019-05-06 11:47:19.779222871 
> +0200
> @@ -0,0 +1,6 @@
> +/* PR tree-optimization/90356 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -frounding-math -fsignaling-nans -fsigned-zeros 
> -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times " \[+-] 0.0;" 32 "optimized" } } */
> +
> +#include "pr90356-1.c"
> --- gcc/testsuite/gcc.dg/tree-ssa/pr90356-4.c.jj      2019-05-06 
> 11:46:02.140467400 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr90356-4.c 2019-05-06 11:47:28.175088284 
> +0200
> @@ -0,0 +1,6 @@
> +/* PR tree-optimization/90356 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -frounding-math -fno-signaling-nans -fsigned-zeros 
> -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times " \[+-] 0.0;" 32 "optimized" } } */
> +
> +#include "pr90356-1.c"
> 
>       Jakub
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany;
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah; HRB 21284 (AG Nürnberg)

Reply via email to