diff --git a/gcc/testsuite/g++.dg/opt/pr94589-5.C b/gcc/testsuite/g++.dg/opt/pr94589-5.C new file mode 100644 index 0000000000000000000000000000000000000000..8d47d4b108291bc1a290ea05cb2db684439cc0ec --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr94589-5.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/opt/pr94589-6.C b/gcc/testsuite/g++.dg/opt/pr94589-6.C new file mode 100644 index 0000000000000000000000000000000000000000..c5036c6f56a9359f90e8a485a7638be6356cf4b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr94589-6.C @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/pr94589-5.c b/gcc/testsuite/gcc.dg/pr94589-5.c new file mode 100644 index 0000000000000000000000000000000000000000..8777fa4d097a0501e60c20e778a6200a9f565cb3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr94589-5.c @@ -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; } diff --git a/gcc/testsuite/gcc.dg/pr94589-6.c b/gcc/testsuite/gcc.dg/pr94589-6.c new file mode 100644 index 0000000000000000000000000000000000000000..2014c1cdcdfc1537e53a4d999d257b0cb3c6cf35 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr94589-6.c @@ -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; +} diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index be6128ed8dfecf4a2eaa9636c4fbfa3935738c4b..8a970b59c6bb24038c1eb24b9865010410831420 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -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);