I've been wondering about the possible performance/missed-optimization impact of my patch for PR middle-end/98420 and similar IEEE correctness fixes that disable constant folding optimizations when worrying about -0.0. In the common situation where the floating point result is used by a FP comparison, there's no distinction between +0.0 and -0.0, so some HONOR_SIGNED_ZEROS optimizations that we'd usually disable, are safe.
Consider the following interesting example: int foo(int x, double y) { return (x * 0.0) < y; } Although we know that x (when converted to double) can't be NaN or Inf, we still worry that for negative values of x that (x * 0.0) may be -0.0 and so perform the multiplication at run-time. But in this case, the result of the comparison (-0.0 < y) will be exactly the same as (+0.0 < y) for any y, hence the above may be safely constant folded to "0.0 < y" avoiding the multiplication at run-time. This patch has been tested on x86_64-pc-linux-gnu with make bootstrap and make -k check with no new failures, and allows GCC to continue to optimize cases that we optimized in GCC 11 (without regard to correctness). Ok for mainline? 2022-03-14 Roger Sayle <ro...@nextmovesoftware.com> gcc/ChangeLog * match.pd (X CMP (Y-Y) -> X CMP 0.0): New transformation. (X CMP (Y * 0.0) -> X CMP 0.0): Likewise. (X CMP X -> true): Test tree_expr_maybe_nan_p instead of HONOR_NANS. (X LTGT X -> false): Enable if X is not tree_expr_maybe_nan_p, as this can't trap/signal. gcc/testsuite/ChangeLog * gcc.dg/fold-compare-9.c: New test case. Thanks in advance, Roger --
diff --git a/gcc/match.pd b/gcc/match.pd index 8b44b5c..f3f7865 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4671,6 +4671,35 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (single_use (@2)) (cmp @0 @1))))) +/* Floating point comparisons can ignore signed zeros. */ +(for cmp (tcc_comparison) + /* Simplify (X - X) CMP Y even with -frounding-math. */ + (simplify + (cmp (minus @0 @0) @1) + (if (FLOAT_TYPE_P (TREE_TYPE (@0)) + && !tree_expr_maybe_nan_p (@0) + && !tree_expr_maybe_infinite_p (@0)) + (cmp { build_zero_cst (TREE_TYPE (@0)); } @1))) + /* Simplify X CMP (Y - Y) even with -frounding-math. */ + (simplify + (cmp @0 (minus @1 @1)) + (if (FLOAT_TYPE_P (TREE_TYPE (@1)) + && !tree_expr_maybe_nan_p (@1) + && !tree_expr_maybe_infinite_p (@1)) + (cmp @0 { build_zero_cst (TREE_TYPE (@1)); }))) + /* Simplify (X * 0.0) CMP Y. */ + (simplify + (cmp (mult @0 real_zerop@1) @2) + (if (!tree_expr_maybe_nan_p (@0) + && !tree_expr_maybe_infinite_p (@0)) + (cmp @1 @2))) + /* Simplify X CMP (Y * 0.0). */ + (simplify + (cmp @0 (mult @1 real_zerop@2)) + (if (!tree_expr_maybe_nan_p (@1) + && !tree_expr_maybe_infinite_p (@0)) + (cmp @0 @2)))) + /* Simplify (x < 0) ^ (y < 0) to (x ^ y) < 0 and (x >= 0) ^ (y >= 0) to (x ^ y) < 0. */ (for cmp (lt ge) @@ -4743,7 +4772,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (simplify (cmp @0 @0) (if (! FLOAT_TYPE_P (TREE_TYPE (@0)) - || ! HONOR_NANS (@0)) + || ! tree_expr_maybe_nan_p (@0)) { constant_boolean_node (true, type); } (if (cmp != EQ_EXPR /* With -ftrapping-math conversion to EQ loses an exception. */ @@ -4755,7 +4784,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cmp @0 @0) (if (cmp != NE_EXPR || ! FLOAT_TYPE_P (TREE_TYPE (@0)) - || ! HONOR_NANS (@0)) + || ! tree_expr_maybe_nan_p (@0)) { constant_boolean_node (false, type); }))) (for cmp (unle unge uneq) (simplify @@ -4767,7 +4796,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (unordered @0 @0))) (simplify (ltgt @0 @0) - (if (!flag_trapping_math) + (if (!flag_trapping_math || !tree_expr_maybe_nan_p (@0)) { constant_boolean_node (false, type); })) /* x == ~x -> false */ diff --git a/gcc/testsuite/gcc.dg/fold-compare-9.c b/gcc/testsuite/gcc.dg/fold-compare-9.c new file mode 100644 index 0000000..e56f63d --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-compare-9.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x, double y) { + return (x * 0.0) < y; +} + +/* { dg-final { scan-tree-dump " y_\[0-9\]\\(D\\) > 0.0" "optimized" } } */