mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 02:44:18 +08:00
phiopt: Improve spaceship_replacement for HONOR_NANS [PR117612]
The following patch optimizes spaceship followed by comparisons of the spaceship value even for floating point spaceship when NaNs can appear. operator<=> for this emits roughly signed char c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; and I believe the /* The optimization may be unsafe due to NaNs. */ comment just isn't true. Sure, the i == j comparison doesn't raise exceptions on qNaNs, but if one of the operands is qNaN, then i == j is false and i < j or i > j is then executed and raises exceptions even on qNaNs. And we can safely optimize say c == -1 comparison after the above into i < j, that also raises exceptions like before and handles NaNs the same way as the original. The only unsafe transormation would be c == 0 or c != 0, turning it into i == j or i != j wouldn't raise exception, so I'm not doing that optimization (but other parts of the compiler optimize the i < j comparison away anyway). Anyway, to match the HONOR_NANS case, we need to verify that the second comparison has true edge to the phi_bb (yielding there -1 or 1), it can't be the false edge because when NaNs are honored, the false edge is for both the case where the inverted comparison is true or when one of the operands is NaN. Similarly we need to ensure that the two non-equality comparisons are the opposite, while for -ffast-math we can in some cases get one comparison x >= 5.0 and the other x > 5.0 and it is fine, because NaN is UB, when NaNs are honored, they must be different to leave the unordered case with 2 value as the last one remaining. The patch also punts if HONOR_NANS and the phi has just 3 arguments instead of 4. When NaNs are honored, we also in some cases need to perform some comparison and then invert its result (so that exceptions are properly thrown and we get the correct result). 2024-11-21 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/94589 PR tree-optimization/117612 * tree-ssa-phiopt.cc (spaceship_replacement): Handle HONOR_NANS (TREE_TYPE (lhs1)) case when possible. * gcc.dg/pr94589-5.c: New test. * gcc.dg/pr94589-6.c: New test. * g++.dg/opt/pr94589-5.C: New test. * g++.dg/opt/pr94589-6.C: New test.
This commit is contained in:
parent
ca7430f145
commit
05ab9447fe
26
gcc/testsuite/g++.dg/opt/pr94589-5.C
Normal file
26
gcc/testsuite/g++.dg/opt/pr94589-5.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR tree-optimization/94589
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target inf }
|
||||
// { dg-options "-O2 -g0 -fdump-tree-optimized" }
|
||||
// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|>|>=) \[ij]_\[0-9]+\\(D\\)" 8 "optimized" } }
|
||||
// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=) 5\\.0" 8 "optimized" } }
|
||||
|
||||
#include <compare>
|
||||
|
||||
#define A __attribute__((noipa))
|
||||
A bool f3 (double i, double j) { auto c = i <=> j; return c > 0; }
|
||||
A bool f4 (double i, double j) { auto c = i <=> j; return c < 0; }
|
||||
A bool f5 (double i, double j) { auto c = i <=> j; return c >= 0; }
|
||||
A bool f6 (double i, double j) { auto c = i <=> j; return c <= 0; }
|
||||
A bool f7 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::less; }
|
||||
A bool f8 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::less; }
|
||||
A bool f11 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::greater; }
|
||||
A bool f12 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::greater; }
|
||||
A bool f15 (double i) { auto c = i <=> 5.0; return c > 0; }
|
||||
A bool f16 (double i) { auto c = i <=> 5.0; return c < 0; }
|
||||
A bool f17 (double i) { auto c = i <=> 5.0; return c >= 0; }
|
||||
A bool f18 (double i) { auto c = i <=> 5.0; return c <= 0; }
|
||||
A bool f19 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::less; }
|
||||
A bool f20 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::less; }
|
||||
A bool f23 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::greater; }
|
||||
A bool f24 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::greater; }
|
138
gcc/testsuite/g++.dg/opt/pr94589-6.C
Normal file
138
gcc/testsuite/g++.dg/opt/pr94589-6.C
Normal file
@ -0,0 +1,138 @@
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target inf }
|
||||
// { dg-options "-O2 -g" }
|
||||
|
||||
#include "pr94589-5.C"
|
||||
|
||||
A bool f1 (double i, double j) { auto c = i <=> j; return c == 0; }
|
||||
A bool f2 (double i, double j) { auto c = i <=> j; return c != 0; }
|
||||
A bool f9 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::equivalent; }
|
||||
A bool f10 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::equivalent; }
|
||||
A bool f13 (double i) { auto c = i <=> 5.0; return c == 0; }
|
||||
A bool f14 (double i) { auto c = i <=> 5.0; return c != 0; }
|
||||
A bool f21 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::equivalent; }
|
||||
A bool f22 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::equivalent; }
|
||||
A bool f25 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::unordered; }
|
||||
A bool f26 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::unordered; }
|
||||
A bool f27 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::unordered; }
|
||||
A bool f28 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::unordered; }
|
||||
|
||||
#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort ()
|
||||
#define D(fn, i, r) if (fn (i) != r) __builtin_abort ()
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
C (f1, 7.0, 8.0, false);
|
||||
C (f1, 8.0, 8.0, true);
|
||||
C (f1, 9.0, 8.0, false);
|
||||
C (f1, __builtin_nan (""), 8.0, false);
|
||||
C (f2, 7.0, 8.0, true);
|
||||
C (f2, 8.0, 8.0, false);
|
||||
C (f2, 9.0, 8.0, true);
|
||||
C (f2, __builtin_nan (""), 8.0, true);
|
||||
C (f3, 7.0, 8.0, false);
|
||||
C (f3, 8.0, 8.0, false);
|
||||
C (f3, 9.0, 8.0, true);
|
||||
C (f3, __builtin_nan (""), 8.0, false);
|
||||
C (f4, 7.0, 8.0, true);
|
||||
C (f4, 8.0, 8.0, false);
|
||||
C (f4, 9.0, 8.0, false);
|
||||
C (f4, __builtin_nan (""), 8.0, false);
|
||||
C (f5, 7.0, 8.0, false);
|
||||
C (f5, 8.0, 8.0, true);
|
||||
C (f5, 9.0, 8.0, true);
|
||||
C (f5, __builtin_nan (""), 8.0, false);
|
||||
C (f6, 7.0, 8.0, true);
|
||||
C (f6, 8.0, 8.0, true);
|
||||
C (f6, 9.0, 8.0, false);
|
||||
C (f6, __builtin_nan (""), 8.0, false);
|
||||
C (f7, 7.0, 8.0, true);
|
||||
C (f7, 8.0, 8.0, false);
|
||||
C (f7, 9.0, 8.0, false);
|
||||
C (f7, __builtin_nan (""), 8.0, false);
|
||||
C (f8, 7.0, 8.0, false);
|
||||
C (f8, 8.0, 8.0, true);
|
||||
C (f8, 9.0, 8.0, true);
|
||||
C (f8, __builtin_nan (""), 8.0, true);
|
||||
C (f9, 7.0, 8.0, false);
|
||||
C (f9, 8.0, 8.0, true);
|
||||
C (f9, 9.0, 8.0, false);
|
||||
C (f9, __builtin_nan (""), 8.0, false);
|
||||
C (f10, 7.0, 8.0, true);
|
||||
C (f10, 8.0, 8.0, false);
|
||||
C (f10, 9.0, 8.0, true);
|
||||
C (f10, __builtin_nan (""), 8.0, true);
|
||||
C (f11, 7.0, 8.0, false);
|
||||
C (f11, 8.0, 8.0, false);
|
||||
C (f11, 9.0, 8.0, true);
|
||||
C (f11, __builtin_nan (""), 8.0, false);
|
||||
C (f12, 7.0, 8.0, true);
|
||||
C (f12, 8.0, 8.0, true);
|
||||
C (f12, 9.0, 8.0, false);
|
||||
C (f12, __builtin_nan (""), 8.0, true);
|
||||
D (f13, 4.0, false);
|
||||
D (f13, 5.0, true);
|
||||
D (f13, 6.0, false);
|
||||
D (f13, __builtin_nan (""), false);
|
||||
D (f14, 4.0, true);
|
||||
D (f14, 5.0, false);
|
||||
D (f14, 6.0, true);
|
||||
D (f14, __builtin_nan (""), true);
|
||||
D (f15, 4.0, false);
|
||||
D (f15, 5.0, false);
|
||||
D (f15, 6.0, true);
|
||||
D (f15, __builtin_nan (""), false);
|
||||
D (f16, 4.0, true);
|
||||
D (f16, 5.0, false);
|
||||
D (f16, 6.0, false);
|
||||
D (f16, __builtin_nan (""), false);
|
||||
D (f17, 4.0, false);
|
||||
D (f17, 5.0, true);
|
||||
D (f17, 6.0, true);
|
||||
D (f17, __builtin_nan (""), false);
|
||||
D (f18, 4.0, true);
|
||||
D (f18, 5.0, true);
|
||||
D (f18, 6.0, false);
|
||||
D (f18, __builtin_nan (""), false);
|
||||
D (f19, 4.0, true);
|
||||
D (f19, 5.0, false);
|
||||
D (f19, 6.0, false);
|
||||
D (f19, __builtin_nan (""), false);
|
||||
D (f20, 4.0, false);
|
||||
D (f20, 5.0, true);
|
||||
D (f20, 6.0, true);
|
||||
D (f20, __builtin_nan (""), true);
|
||||
D (f21, 4.0, false);
|
||||
D (f21, 5.0, true);
|
||||
D (f21, 6.0, false);
|
||||
D (f21, __builtin_nan (""), false);
|
||||
D (f22, 4.0, true);
|
||||
D (f22, 5.0, false);
|
||||
D (f22, 6.0, true);
|
||||
D (f22, __builtin_nan (""), true);
|
||||
D (f23, 4.0, false);
|
||||
D (f23, 5.0, false);
|
||||
D (f23, 6.0, true);
|
||||
D (f23, __builtin_nan (""), false);
|
||||
D (f24, 4.0, true);
|
||||
D (f24, 5.0, true);
|
||||
D (f24, 6.0, false);
|
||||
D (f24, __builtin_nan (""), true);
|
||||
C (f25, 7.0, 8.0, false);
|
||||
C (f25, 8.0, 8.0, false);
|
||||
C (f25, 9.0, 8.0, false);
|
||||
C (f25, __builtin_nan (""), 8.0, true);
|
||||
C (f26, 7.0, 8.0, true);
|
||||
C (f26, 8.0, 8.0, true);
|
||||
C (f26, 9.0, 8.0, true);
|
||||
C (f26, __builtin_nan (""), 8.0, false);
|
||||
D (f27, 4.0, false);
|
||||
D (f27, 5.0, false);
|
||||
D (f27, 6.0, false);
|
||||
D (f27, __builtin_nan (""), true);
|
||||
D (f28, 4.0, true);
|
||||
D (f28, 5.0, true);
|
||||
D (f28, 6.0, true);
|
||||
D (f28, __builtin_nan (""), false);
|
||||
}
|
35
gcc/testsuite/gcc.dg/pr94589-5.c
Normal file
35
gcc/testsuite/gcc.dg/pr94589-5.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* PR tree-optimization/94589 */
|
||||
/* { dg-do compile { target inf } } */
|
||||
/* { dg-options "-O2 -g0 -fdump-tree-optimized" } */
|
||||
/* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|>|>=) \[ij]_\[0-9]+\\(D\\)" 14 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=) 5\\.0" 14 "optimized" } } */
|
||||
|
||||
#define A __attribute__((noipa))
|
||||
A int f3 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c > 0; }
|
||||
A int f4 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c < 0; }
|
||||
A int f5 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c >= 0; }
|
||||
A int f6 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c <= 0; }
|
||||
A int f7 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == -1; }
|
||||
A int f8 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != -1; }
|
||||
A int f9 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c > -1; }
|
||||
A int f10 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c <= -1; }
|
||||
A int f11 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == 1; }
|
||||
A int f12 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != 1; }
|
||||
A int f13 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c < 1; }
|
||||
A int f14 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c >= 1; }
|
||||
A int f17 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c > 0; }
|
||||
A int f18 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c < 0; }
|
||||
A int f19 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c >= 0; }
|
||||
A int f20 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c <= 0; }
|
||||
A int f21 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == -1; }
|
||||
A int f22 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != -1; }
|
||||
A int f23 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c > -1; }
|
||||
A int f24 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c <= -1; }
|
||||
A int f25 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == 1; }
|
||||
A int f26 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != 1; }
|
||||
A int f27 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c < 1; }
|
||||
A int f28 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c >= 1; }
|
||||
A int f29 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return (c & ~1) == 0; }
|
||||
A int f30 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return (c & ~1) != 0; }
|
||||
A int f31 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return (c & ~1) == 0; }
|
||||
A int f32 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return (c & ~1) != 0; }
|
146
gcc/testsuite/gcc.dg/pr94589-6.c
Normal file
146
gcc/testsuite/gcc.dg/pr94589-6.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* { dg-do run { target inf } } */
|
||||
/* { dg-options "-O2 -g" } */
|
||||
|
||||
#include "pr94589-5.c"
|
||||
|
||||
A int f1 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == 0; }
|
||||
A int f2 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != 0; }
|
||||
A int f15 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == 0; }
|
||||
A int f16 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != 0; }
|
||||
|
||||
#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort ()
|
||||
#define D(fn, i, r) if (fn (i) != r) __builtin_abort ()
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
C (f1, 7.0, 8.0, 0);
|
||||
C (f1, 8.0, 8.0, 1);
|
||||
C (f1, 9.0, 8.0, 0);
|
||||
C (f1, __builtin_nan (""), 8.0, 0);
|
||||
C (f2, 7.0, 8.0, 1);
|
||||
C (f2, 8.0, 8.0, 0);
|
||||
C (f2, 9.0, 8.0, 1);
|
||||
C (f2, __builtin_nan (""), 8.0, 1);
|
||||
C (f3, 7.0, 8.0, 0);
|
||||
C (f3, 8.0, 8.0, 0);
|
||||
C (f3, 9.0, 8.0, 1);
|
||||
C (f3, __builtin_nan (""), 8.0, 1);
|
||||
C (f4, 7.0, 8.0, 1);
|
||||
C (f4, 8.0, 8.0, 0);
|
||||
C (f4, 9.0, 8.0, 0);
|
||||
C (f4, __builtin_nan (""), 8.0, 0);
|
||||
C (f5, 7.0, 8.0, 0);
|
||||
C (f5, 8.0, 8.0, 1);
|
||||
C (f5, 9.0, 8.0, 1);
|
||||
C (f5, __builtin_nan (""), 8.0, 1);
|
||||
C (f6, 7.0, 8.0, 1);
|
||||
C (f6, 8.0, 8.0, 1);
|
||||
C (f6, 9.0, 8.0, 0);
|
||||
C (f6, __builtin_nan (""), 8.0, 0);
|
||||
C (f7, 7.0, 8.0, 1);
|
||||
C (f7, 8.0, 8.0, 0);
|
||||
C (f7, 9.0, 8.0, 0);
|
||||
C (f7, __builtin_nan (""), 8.0, 0);
|
||||
C (f8, 7.0, 8.0, 0);
|
||||
C (f8, 8.0, 8.0, 1);
|
||||
C (f8, 9.0, 8.0, 1);
|
||||
C (f8, __builtin_nan (""), 8.0, 1);
|
||||
C (f9, 7.0, 8.0, 0);
|
||||
C (f9, 8.0, 8.0, 1);
|
||||
C (f9, 9.0, 8.0, 1);
|
||||
C (f9, __builtin_nan (""), 8.0, 1);
|
||||
C (f10, 7.0, 8.0, 1);
|
||||
C (f10, 8.0, 8.0, 0);
|
||||
C (f10, 9.0, 8.0, 0);
|
||||
C (f10, __builtin_nan (""), 8.0, 0);
|
||||
C (f11, 7.0, 8.0, 0);
|
||||
C (f11, 8.0, 8.0, 0);
|
||||
C (f11, 9.0, 8.0, 1);
|
||||
C (f11, __builtin_nan (""), 8.0, 0);
|
||||
C (f12, 7.0, 8.0, 1);
|
||||
C (f12, 8.0, 8.0, 1);
|
||||
C (f12, 9.0, 8.0, 0);
|
||||
C (f12, __builtin_nan (""), 8.0, 1);
|
||||
C (f13, 7.0, 8.0, 1);
|
||||
C (f13, 8.0, 8.0, 1);
|
||||
C (f13, 9.0, 8.0, 0);
|
||||
C (f13, __builtin_nan (""), 8.0, 0);
|
||||
C (f14, 7.0, 8.0, 0);
|
||||
C (f14, 8.0, 8.0, 0);
|
||||
C (f14, 9.0, 8.0, 1);
|
||||
C (f14, __builtin_nan (""), 8.0, 1);
|
||||
D (f15, 4.0, 0);
|
||||
D (f15, 5.0, 1);
|
||||
D (f15, 6.0, 0);
|
||||
D (f15, __builtin_nan (""), 0);
|
||||
D (f16, 4.0, 1);
|
||||
D (f16, 5.0, 0);
|
||||
D (f16, 6.0, 1);
|
||||
D (f16, __builtin_nan (""), 1);
|
||||
D (f17, 4.0, 0);
|
||||
D (f17, 5.0, 0);
|
||||
D (f17, 6.0, 1);
|
||||
D (f17, __builtin_nan (""), 1);
|
||||
D (f18, 4.0, 1);
|
||||
D (f18, 5.0, 0);
|
||||
D (f18, 6.0, 0);
|
||||
D (f18, __builtin_nan (""), 0);
|
||||
D (f19, 4.0, 0);
|
||||
D (f19, 5.0, 1);
|
||||
D (f19, 6.0, 1);
|
||||
D (f19, __builtin_nan (""), 1);
|
||||
D (f20, 4.0, 1);
|
||||
D (f20, 5.0, 1);
|
||||
D (f20, 6.0, 0);
|
||||
D (f20, __builtin_nan (""), 0);
|
||||
D (f21, 4.0, 1);
|
||||
D (f21, 5.0, 0);
|
||||
D (f21, 6.0, 0);
|
||||
D (f21, __builtin_nan (""), 0);
|
||||
D (f22, 4.0, 0);
|
||||
D (f22, 5.0, 1);
|
||||
D (f22, 6.0, 1);
|
||||
D (f22, __builtin_nan (""), 1);
|
||||
D (f23, 4.0, 0);
|
||||
D (f23, 5.0, 1);
|
||||
D (f23, 6.0, 1);
|
||||
D (f23, __builtin_nan (""), 1);
|
||||
D (f24, 4.0, 1);
|
||||
D (f24, 5.0, 0);
|
||||
D (f24, 6.0, 0);
|
||||
D (f24, __builtin_nan (""), 0);
|
||||
D (f25, 4.0, 0);
|
||||
D (f25, 5.0, 0);
|
||||
D (f25, 6.0, 1);
|
||||
D (f25, __builtin_nan (""), 0);
|
||||
D (f26, 4.0, 1);
|
||||
D (f26, 5.0, 1);
|
||||
D (f26, 6.0, 0);
|
||||
D (f26, __builtin_nan (""), 1);
|
||||
D (f27, 4.0, 1);
|
||||
D (f27, 5.0, 1);
|
||||
D (f27, 6.0, 0);
|
||||
D (f27, __builtin_nan (""), 0);
|
||||
D (f28, 4.0, 0);
|
||||
D (f28, 5.0, 0);
|
||||
D (f28, 6.0, 1);
|
||||
D (f28, __builtin_nan (""), 1);
|
||||
C (f29, 7.0, 8.0, 0);
|
||||
C (f29, 8.0, 8.0, 1);
|
||||
C (f29, 9.0, 8.0, 1);
|
||||
C (f29, __builtin_nan (""), 8.0, 0);
|
||||
C (f30, 7.0, 8.0, 1);
|
||||
C (f30, 8.0, 8.0, 0);
|
||||
C (f30, 9.0, 8.0, 0);
|
||||
C (f30, __builtin_nan (""), 8.0, 1);
|
||||
D (f31, 4.0, 0);
|
||||
D (f31, 5.0, 1);
|
||||
D (f31, 6.0, 1);
|
||||
D (f31, __builtin_nan (""), 0);
|
||||
D (f32, 4.0, 1);
|
||||
D (f32, 5.0, 0);
|
||||
D (f32, 6.0, 0);
|
||||
D (f32, __builtin_nan (""), 1);
|
||||
return 0;
|
||||
}
|
@ -2588,9 +2588,6 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
}
|
||||
tree lhs1 = gimple_cond_lhs (cond1);
|
||||
tree rhs1 = gimple_cond_rhs (cond1);
|
||||
/* The optimization may be unsafe due to NaNs. */
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
return false;
|
||||
if (TREE_CODE (lhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs1))
|
||||
return false;
|
||||
if (TREE_CODE (rhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1))
|
||||
@ -2681,6 +2678,9 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
{
|
||||
if (absu_hwi (tree_to_shwi (arg2)) != 1)
|
||||
return false;
|
||||
if ((cond2_phi_edge->flags & EDGE_FALSE_VALUE)
|
||||
&& HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
return false;
|
||||
if (e1->flags & EDGE_TRUE_VALUE)
|
||||
{
|
||||
if (tree_to_shwi (arg0) != 2
|
||||
@ -2708,14 +2708,20 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
phi_bb:;
|
||||
is ok, but if x and y are swapped in one of the comparisons,
|
||||
or the comparisons are the same and operands not swapped,
|
||||
or the true and false edges are swapped, it is not. */
|
||||
or the true and false edges are swapped, it is not.
|
||||
For HONOR_NANS, the edge flags are irrelevant and the comparisons
|
||||
must be different for non-swapped operands and same for swapped
|
||||
operands. */
|
||||
if ((lhs2 == lhs1)
|
||||
^ (((cond2_phi_edge->flags
|
||||
& ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
|
||||
? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)
|
||||
!= ((e1->flags
|
||||
& ((cmp1 == LT_EXPR || cmp1 == LE_EXPR)
|
||||
? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)))
|
||||
^ (HONOR_NANS (TREE_TYPE (lhs1))
|
||||
? ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
|
||||
!= (cmp1 == LT_EXPR || cmp1 == LE_EXPR))
|
||||
: (((cond2_phi_edge->flags
|
||||
& ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
|
||||
? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)
|
||||
!= ((e1->flags
|
||||
& ((cmp1 == LT_EXPR || cmp1 == LE_EXPR)
|
||||
? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0))))
|
||||
return false;
|
||||
if (!single_pred_p (cond2_bb) || !cond_only_block_p (cond2_bb))
|
||||
return false;
|
||||
@ -2754,7 +2760,8 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
}
|
||||
else if (absu_hwi (tree_to_shwi (arg0)) != 1
|
||||
|| absu_hwi (tree_to_shwi (arg1)) != 1
|
||||
|| wi::to_widest (arg0) == wi::to_widest (arg1))
|
||||
|| wi::to_widest (arg0) == wi::to_widest (arg1)
|
||||
|| HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
return false;
|
||||
|
||||
if (!integer_zerop (arg3) || (cmp3 != EQ_EXPR && cmp3 != NE_EXPR))
|
||||
@ -2772,10 +2779,11 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
one_cmp = GT_EXPR;
|
||||
|
||||
enum tree_code res_cmp;
|
||||
bool negate_p = false;
|
||||
switch (cmp)
|
||||
{
|
||||
case EQ_EXPR:
|
||||
if (integer_zerop (rhs))
|
||||
if (integer_zerop (rhs) && !HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
res_cmp = EQ_EXPR;
|
||||
else if (integer_minus_onep (rhs))
|
||||
res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
|
||||
@ -2785,7 +2793,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
return false;
|
||||
break;
|
||||
case NE_EXPR:
|
||||
if (integer_zerop (rhs))
|
||||
if (integer_zerop (rhs) && !HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
res_cmp = NE_EXPR;
|
||||
else if (integer_minus_onep (rhs))
|
||||
res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
|
||||
@ -2793,12 +2801,18 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
|
||||
else
|
||||
return false;
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
negate_p = true;
|
||||
break;
|
||||
case LT_EXPR:
|
||||
if (integer_onep (rhs))
|
||||
res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
|
||||
else if (integer_zerop (rhs))
|
||||
res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
|
||||
{
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)) && orig_use_lhs)
|
||||
negate_p = true;
|
||||
res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
@ -2817,12 +2831,22 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
res_cmp = one_cmp;
|
||||
else
|
||||
return false;
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
negate_p = true;
|
||||
break;
|
||||
case GE_EXPR:
|
||||
if (integer_zerop (rhs))
|
||||
res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
|
||||
{
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)) && !orig_use_lhs)
|
||||
negate_p = true;
|
||||
res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
|
||||
}
|
||||
else if (integer_onep (rhs))
|
||||
res_cmp = one_cmp;
|
||||
{
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
negate_p = true;
|
||||
res_cmp = one_cmp;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
@ -2830,23 +2854,37 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
tree clhs1 = lhs1, crhs1 = rhs1;
|
||||
if (negate_p)
|
||||
{
|
||||
if (cfun->can_throw_non_call_exceptions)
|
||||
return false;
|
||||
res_cmp = invert_tree_comparison (res_cmp, false);
|
||||
clhs1 = make_ssa_name (boolean_type_node);
|
||||
gimple *g = gimple_build_assign (clhs1, res_cmp, lhs1, rhs1);
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
crhs1 = boolean_false_node;
|
||||
res_cmp = EQ_EXPR;
|
||||
}
|
||||
|
||||
if (gimple_code (use_stmt) == GIMPLE_COND)
|
||||
{
|
||||
gcond *use_cond = as_a <gcond *> (use_stmt);
|
||||
gimple_cond_set_code (use_cond, res_cmp);
|
||||
gimple_cond_set_lhs (use_cond, lhs1);
|
||||
gimple_cond_set_rhs (use_cond, rhs1);
|
||||
gimple_cond_set_lhs (use_cond, clhs1);
|
||||
gimple_cond_set_rhs (use_cond, crhs1);
|
||||
}
|
||||
else if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
|
||||
{
|
||||
gimple_assign_set_rhs_code (use_stmt, res_cmp);
|
||||
gimple_assign_set_rhs1 (use_stmt, lhs1);
|
||||
gimple_assign_set_rhs2 (use_stmt, rhs1);
|
||||
gimple_assign_set_rhs1 (use_stmt, clhs1);
|
||||
gimple_assign_set_rhs2 (use_stmt, crhs1);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree cond = build2 (res_cmp, TREE_TYPE (gimple_assign_rhs1 (use_stmt)),
|
||||
lhs1, rhs1);
|
||||
clhs1, crhs1);
|
||||
gimple_assign_set_rhs1 (use_stmt, cond);
|
||||
}
|
||||
update_stmt (use_stmt);
|
||||
@ -2890,14 +2928,31 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
# DEBUG D#2 => i_2(D) == j_3(D) ? 0 : D#1
|
||||
where > stands for the comparison that yielded 1
|
||||
and replace debug uses of phi result with that D#2.
|
||||
Ignore the value of 2, because if NaNs aren't expected,
|
||||
all floating point numbers should be comparable. */
|
||||
Ignore the value of 2 if !HONOR_NANS, because if NaNs
|
||||
aren't expected, all floating point numbers should be
|
||||
comparable. If HONOR_NANS, emit something like:
|
||||
# DEBUG D#1 => i_2(D) < j_3(D) ? -1 : 2
|
||||
# DEBUG D#2 => i_2(D) > j_3(D) ? 1 : D#1
|
||||
# DEBUG D#3 => i_2(D) == j_3(D) ? 0 : D#2
|
||||
instead. */
|
||||
gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (phi));
|
||||
tree type = TREE_TYPE (phires);
|
||||
tree minus_one = build_int_cst (type, -1);
|
||||
if (HONOR_NANS (TREE_TYPE (lhs1)))
|
||||
{
|
||||
tree temp3 = build_debug_expr_decl (type);
|
||||
tree t = build2 (one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR,
|
||||
boolean_type_node, lhs1, rhs2);
|
||||
t = build3 (COND_EXPR, type, t, minus_one,
|
||||
build_int_cst (type, 2));
|
||||
gimple *g = gimple_build_debug_bind (temp3, t, phi);
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
minus_one = temp3;
|
||||
}
|
||||
tree temp1 = build_debug_expr_decl (type);
|
||||
tree t = build2 (one_cmp, boolean_type_node, lhs1, rhs2);
|
||||
t = build3 (COND_EXPR, type, t, build_one_cst (type),
|
||||
build_int_cst (type, -1));
|
||||
minus_one);
|
||||
gimple *g = gimple_build_debug_bind (temp1, t, phi);
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
tree temp2 = build_debug_expr_decl (type);
|
||||
@ -2908,13 +2963,19 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
|
||||
replace_uses_by (phires, temp2);
|
||||
if (orig_use_lhs)
|
||||
{
|
||||
if (has_cast_debug_uses)
|
||||
if (has_cast_debug_uses
|
||||
|| (HONOR_NANS (TREE_TYPE (lhs1)) && !is_cast))
|
||||
{
|
||||
tree temp3 = make_node (DEBUG_EXPR_DECL);
|
||||
DECL_ARTIFICIAL (temp3) = 1;
|
||||
TREE_TYPE (temp3) = TREE_TYPE (orig_use_lhs);
|
||||
SET_DECL_MODE (temp3, TYPE_MODE (type));
|
||||
t = fold_convert (TREE_TYPE (temp3), temp2);
|
||||
if (has_cast_debug_uses)
|
||||
t = fold_convert (TREE_TYPE (temp3), temp2);
|
||||
else
|
||||
t = build2 (BIT_AND_EXPR, TREE_TYPE (temp3),
|
||||
temp2, build_int_cst (TREE_TYPE (temp3),
|
||||
~1));
|
||||
g = gimple_build_debug_bind (temp3, t, phi);
|
||||
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
|
||||
replace_uses_by (orig_use_lhs, temp3);
|
||||
|
Loading…
Reference in New Issue
Block a user