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);