diff options
author | Jakub Jelinek <jakub@redhat.com> | 2021-01-22 11:50:18 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2021-01-22 11:51:22 +0100 |
commit | 36fe1cdc9534c36c02803ce97557130354d2b2a0 (patch) | |
tree | f1b9475408940c2922bb3d9252e236181e7fb495 /gcc/match.pd | |
parent | e287a2a11d7958e5d9f7c6172e59cc83495e393a (diff) | |
download | gcc-36fe1cdc9534c36c02803ce97557130354d2b2a0.zip gcc-36fe1cdc9534c36c02803ce97557130354d2b2a0.tar.gz gcc-36fe1cdc9534c36c02803ce97557130354d2b2a0.tar.bz2 |
match.pd: Replace incorrect simplifications into copysign [PR90248]
In the PR Andrew said he has implemented a simplification that has been
added to LLVM, but that actually is not true, what is in there are
X * (X cmp 0.0 ? +-1.0 : -+1.0) simplifications into +-abs(X)
but what has been added into GCC are (X cmp 0.0 ? +-1.0 : -+1.0)
simplifications into copysign(1, +-X) and then
X * copysign (1, +-X) into +-abs (X).
The problem is with the (X cmp 0.0 ? +-1.0 : -+1.0) simplifications,
they don't work correctly when X is zero.
E.g.
(X > 0.0 ? 1.0 : -1.0)
is -1.0 when X is either -0.0 or 0.0, but copysign will make it return
1.0 for 0.0 and -1.0 only for -0.0.
(X >= 0.0 ? 1.0 : -1.0)
is 1.0 when X is either -0.0 or 0.0, but copysign will make it return
still 1.0 for 0.0 and -1.0 for -0.0.
The simplifications were guarded on !HONOR_SIGNED_ZEROS, but as discussed in
the PR, that option doesn't mean that -0.0 will not ever appear as operand
of some operation, it is hard to guarantee that without compiler adding
canonicalizations of -0.0 to 0.0 after most of the operations and thus
making it very slow, but that the user asserts that he doesn't care if the result
of operations will be 0.0 or -0.0. Not to mention that some of the
transformations are incorrect even for positive 0.0.
So, instead of those simplifications this patch recognizes patterns where
those ?: expressions are multiplied by X, directly into +-abs.
That works fine even for 0.0 and -0.0 (as long as we don't care about
whether the result is exactly 0.0 or -0.0 in those cases), because
whether the result of copysign is -1.0 or 1.0 doesn't matter when it is
multiplied by 0.0 or -0.0.
As a follow-up, maybe we should add the simplification mentioned in the PR,
in particular doing copysign by hand through
VIEW_CONVERT_EXPR <int, float_X> < 0 ? -float_constant : float_constant
into copysign (float_constant, float_X). But I think that would need to be
done in phiopt.
2021-01-22 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/90248
* match.pd (X cmp 0.0 ? 1.0 : -1.0 -> copysign(1, +-X),
X cmp 0.0 ? -1.0 : +1.0 -> copysign(1, -+X)): Remove
simplifications.
(X * (X cmp 0.0 ? 1.0 : -1.0) -> +-abs(X),
X * (X cmp 0.0 ? -1.0 : 1.0) -> +-abs(X)): New simplifications.
* gcc.dg/tree-ssa/copy-sign-1.c: Don't expect any copysign
builtins.
* gcc.dg/pr90248.c: New test.
Diffstat (limited to 'gcc/match.pd')
-rw-r--r-- | gcc/match.pd | 46 |
1 files changed, 16 insertions, 30 deletions
diff --git a/gcc/match.pd b/gcc/match.pd index 05e7ba9..17c35ee4 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -253,36 +253,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (for cmp (gt ge lt le) outp (convert convert negate negate) outn (negate negate convert convert) - /* Transform (X > 0.0 ? 1.0 : -1.0) into copysign(1, X). */ - /* Transform (X >= 0.0 ? 1.0 : -1.0) into copysign(1, X). */ - /* Transform (X < 0.0 ? 1.0 : -1.0) into copysign(1,-X). */ - /* Transform (X <= 0.0 ? 1.0 : -1.0) into copysign(1,-X). */ - (simplify - (cond (cmp @0 real_zerop) real_onep@1 real_minus_onep) - (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type) - && types_match (type, TREE_TYPE (@0))) - (switch - (if (types_match (type, float_type_node)) - (BUILT_IN_COPYSIGNF @1 (outp @0))) - (if (types_match (type, double_type_node)) - (BUILT_IN_COPYSIGN @1 (outp @0))) - (if (types_match (type, long_double_type_node)) - (BUILT_IN_COPYSIGNL @1 (outp @0)))))) - /* Transform (X > 0.0 ? -1.0 : 1.0) into copysign(1,-X). */ - /* Transform (X >= 0.0 ? -1.0 : 1.0) into copysign(1,-X). */ - /* Transform (X < 0.0 ? -1.0 : 1.0) into copysign(1,X). */ - /* Transform (X <= 0.0 ? -1.0 : 1.0) into copysign(1,X). */ - (simplify - (cond (cmp @0 real_zerop) real_minus_onep real_onep@1) - (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type) - && types_match (type, TREE_TYPE (@0))) - (switch - (if (types_match (type, float_type_node)) - (BUILT_IN_COPYSIGNF @1 (outn @0))) - (if (types_match (type, double_type_node)) - (BUILT_IN_COPYSIGN @1 (outn @0))) - (if (types_match (type, long_double_type_node)) - (BUILT_IN_COPYSIGNL @1 (outn @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). */ + /* Transform X * (X < 0.0 ? 1.0 : -1.0) into -abs(X). */ + /* 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)) + (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). */ + /* Transform X * (X < 0.0 ? -1.0 : 1.0) into abs(X). */ + /* 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)) + (outn (abs @0))))) /* Transform X * copysign (1.0, X) into abs(X). */ (simplify |