diff options
Diffstat (limited to '0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch')
| -rw-r--r-- | 0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch | 1067 | 
1 files changed, 1067 insertions, 0 deletions
diff --git a/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch b/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch new file mode 100644 index 0000000..473dee8 --- /dev/null +++ b/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch @@ -0,0 +1,1067 @@ +From 02313ab8cf7eb4defc1482ece48c07c2d8c77be9 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Thu, 6 May 2021 10:15:40 +0200 +Subject: [PATCH 08/35] [Backport] phiopt: Optimize (x <=> y) cmp z [PR94589] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=ad96c867e173c1ebcfc201b201adac5095683a08 + +genericize_spaceship genericizes i <=> j to approximately +({ int c; if (i == j) c = 0; else if (i < j) c = -1; else c = 1; c; }) +for strong ordering and +({ int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; c; }) +for partial ordering. +The C++ standard supports then == or != comparisons of that against +strong/partial ordering enums, or </<=/==/!=/>/>= comparisons of <=> result +against literal 0. + +In some cases we already optimize that but in many cases we keep performing +all the 2 or 3 comparisons, compute the spaceship value and then compare +that. + +The following patch recognizes those patterns if the <=> operands are +integral types or floating point (the latter only for -ffast-math) and +optimizes it to the single comparison that is needed (plus adds debug stmts +if needed for the spaceship result). + +There is one thing I'd like to address in a follow-up: the pr94589-2.C +testcase should be matching just 12 times each, but runs +into operator>=(partial_ordering, unspecified) being defined as +(_M_value&1)==_M_value +rather than _M_value>=0.  When not honoring NaNs, the 2 case should be +unreachable and so (_M_value&1)==_M_value is then equivalent to _M_value>=0, +but is not a single use but two uses.  I'll need to pattern match that case +specially. + +2021-05-06  Jakub Jelinek  <jakub@redhat.com> + +	PR tree-optimization/94589 +	* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Call +	spaceship_replacement. +	(cond_only_block_p, spaceship_replacement): New functions. + +	* gcc.dg/pr94589-1.c: New test. +	* gcc.dg/pr94589-2.c: New test. +	* gcc.dg/pr94589-3.c: New test. +	* gcc.dg/pr94589-4.c: New test. +	* g++.dg/opt/pr94589-1.C: New test. +	* g++.dg/opt/pr94589-2.C: New test. +	* g++.dg/opt/pr94589-3.C: New test. +	* g++.dg/opt/pr94589-4.C: New test. +--- + gcc/testsuite/g++.dg/opt/pr94589-1.C |  33 +++ + gcc/testsuite/g++.dg/opt/pr94589-2.C |  33 +++ + gcc/testsuite/g++.dg/opt/pr94589-3.C |  84 ++++++ + gcc/testsuite/g++.dg/opt/pr94589-4.C |  84 ++++++ + gcc/testsuite/gcc.dg/pr94589-1.c     |  35 +++ + gcc/testsuite/gcc.dg/pr94589-2.c     |  35 +++ + gcc/testsuite/gcc.dg/pr94589-3.c     |  97 ++++++ + gcc/testsuite/gcc.dg/pr94589-4.c     |  97 ++++++ + gcc/tree-ssa-phiopt.c                | 424 +++++++++++++++++++++++++++ + 9 files changed, 922 insertions(+) + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-1.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-2.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-3.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-4.C + create mode 100644 gcc/testsuite/gcc.dg/pr94589-1.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-2.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-3.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-4.c + +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-1.C b/gcc/testsuite/g++.dg/opt/pr94589-1.C +new file mode 100644 +index 000000000..d1cc5050c +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-1.C +@@ -0,0 +1,33 @@ ++// PR tree-optimization/94589 ++// { dg-do compile { target c++20 } } ++// { dg-options "-O2 -g0 -fdump-tree-optimized" } ++// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" } } ++// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[45]" 12 "optimized" } } ++ ++#include <compare> ++ ++#define A __attribute__((noipa)) ++A bool f1 (int i, int j) { auto c = i <=> j; return c == 0; } ++A bool f2 (int i, int j) { auto c = i <=> j; return c != 0; } ++A bool f3 (int i, int j) { auto c = i <=> j; return c > 0; } ++A bool f4 (int i, int j) { auto c = i <=> j; return c < 0; } ++A bool f5 (int i, int j) { auto c = i <=> j; return c >= 0; } ++A bool f6 (int i, int j) { auto c = i <=> j; return c <= 0; } ++A bool f7 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::less; } ++A bool f8 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::less; } ++A bool f9 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::equal; } ++A bool f10 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::equal; } ++A bool f11 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::greater; } ++A bool f12 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::greater; } ++A bool f13 (int i) { auto c = i <=> 5; return c == 0; } ++A bool f14 (int i) { auto c = i <=> 5; return c != 0; } ++A bool f15 (int i) { auto c = i <=> 5; return c > 0; } ++A bool f16 (int i) { auto c = i <=> 5; return c < 0; } ++A bool f17 (int i) { auto c = i <=> 5; return c >= 0; } ++A bool f18 (int i) { auto c = i <=> 5; return c <= 0; } ++A bool f19 (int i) { auto c = i <=> 5; return c == std::strong_ordering::less; } ++A bool f20 (int i) { auto c = i <=> 5; return c != std::strong_ordering::less; } ++A bool f21 (int i) { auto c = i <=> 5; return c == std::strong_ordering::equal; } ++A bool f22 (int i) { auto c = i <=> 5; return c != std::strong_ordering::equal; } ++A bool f23 (int i) { auto c = i <=> 5; return c == std::strong_ordering::greater; } ++A bool f24 (int i) { auto c = i <=> 5; return c != std::strong_ordering::greater; } +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-2.C b/gcc/testsuite/g++.dg/opt/pr94589-2.C +new file mode 100644 +index 000000000..dda947e22 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-2.C +@@ -0,0 +1,33 @@ ++// PR tree-optimization/94589 ++// { dg-do compile { target c++20 } } ++// { dg-options "-O2 -g0 -ffast-math -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" } } ++ ++#include <compare> ++ ++#define A __attribute__((noipa)) ++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 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 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 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 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 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 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 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-3.C b/gcc/testsuite/g++.dg/opt/pr94589-3.C +new file mode 100644 +index 000000000..725b81f56 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-3.C +@@ -0,0 +1,84 @@ ++// { dg-do run { target c++20 } } ++// { dg-options "-O2 -g" } ++ ++#include "pr94589-1.C" ++ ++#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, 8, false); ++  C (f1, 8, 8, true); ++  C (f1, 9, 8, false); ++  C (f2, 7, 8, true); ++  C (f2, 8, 8, false); ++  C (f2, 9, 8, true); ++  C (f3, 7, 8, false); ++  C (f3, 8, 8, false); ++  C (f3, 9, 8, true); ++  C (f4, 7, 8, true); ++  C (f4, 8, 8, false); ++  C (f4, 9, 8, false); ++  C (f5, 7, 8, false); ++  C (f5, 8, 8, true); ++  C (f5, 9, 8, true); ++  C (f6, 7, 8, true); ++  C (f6, 8, 8, true); ++  C (f6, 9, 8, false); ++  C (f7, 7, 8, true); ++  C (f7, 8, 8, false); ++  C (f7, 9, 8, false); ++  C (f8, 7, 8, false); ++  C (f8, 8, 8, true); ++  C (f8, 9, 8, true); ++  C (f9, 7, 8, false); ++  C (f9, 8, 8, true); ++  C (f9, 9, 8, false); ++  C (f10, 7, 8, true); ++  C (f10, 8, 8, false); ++  C (f10, 9, 8, true); ++  C (f11, 7, 8, false); ++  C (f11, 8, 8, false); ++  C (f11, 9, 8, true); ++  C (f12, 7, 8, true); ++  C (f12, 8, 8, true); ++  C (f12, 9, 8, false); ++  D (f13, 4, false); ++  D (f13, 5, true); ++  D (f13, 6, false); ++  D (f14, 4, true); ++  D (f14, 5, false); ++  D (f14, 6, true); ++  D (f15, 4, false); ++  D (f15, 5, false); ++  D (f15, 6, true); ++  D (f16, 4, true); ++  D (f16, 5, false); ++  D (f16, 6, false); ++  D (f17, 4, false); ++  D (f17, 5, true); ++  D (f17, 6, true); ++  D (f18, 4, true); ++  D (f18, 5, true); ++  D (f18, 6, false); ++  D (f19, 4, true); ++  D (f19, 5, false); ++  D (f19, 6, false); ++  D (f20, 4, false); ++  D (f20, 5, true); ++  D (f20, 6, true); ++  D (f21, 4, false); ++  D (f21, 5, true); ++  D (f21, 6, false); ++  D (f22, 4, true); ++  D (f22, 5, false); ++  D (f22, 6, true); ++  D (f23, 4, false); ++  D (f23, 5, false); ++  D (f23, 6, true); ++  D (f24, 4, true); ++  D (f24, 5, true); ++  D (f24, 6, false); ++} +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-4.C b/gcc/testsuite/g++.dg/opt/pr94589-4.C +new file mode 100644 +index 000000000..256a45580 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-4.C +@@ -0,0 +1,84 @@ ++// { dg-do run { target c++20 } } ++// { dg-options "-O2 -g -ffast-math" } ++ ++#include "pr94589-2.C" ++ ++#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 (f2, 7.0, 8.0, true); ++  C (f2, 8.0, 8.0, false); ++  C (f2, 9.0, 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 (f4, 7.0, 8.0, true); ++  C (f4, 8.0, 8.0, false); ++  C (f4, 9.0, 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 (f6, 7.0, 8.0, true); ++  C (f6, 8.0, 8.0, true); ++  C (f6, 9.0, 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 (f8, 7.0, 8.0, false); ++  C (f8, 8.0, 8.0, true); ++  C (f8, 9.0, 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 (f10, 7.0, 8.0, true); ++  C (f10, 8.0, 8.0, false); ++  C (f10, 9.0, 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 (f12, 7.0, 8.0, true); ++  C (f12, 8.0, 8.0, true); ++  C (f12, 9.0, 8.0, false); ++  D (f13, 4.0, false); ++  D (f13, 5.0, true); ++  D (f13, 6.0, false); ++  D (f14, 4.0, true); ++  D (f14, 5.0, false); ++  D (f14, 6.0, true); ++  D (f15, 4.0, false); ++  D (f15, 5.0, false); ++  D (f15, 6.0, true); ++  D (f16, 4.0, true); ++  D (f16, 5.0, false); ++  D (f16, 6.0, false); ++  D (f17, 4.0, false); ++  D (f17, 5.0, true); ++  D (f17, 6.0, true); ++  D (f18, 4.0, true); ++  D (f18, 5.0, true); ++  D (f18, 6.0, false); ++  D (f19, 4.0, true); ++  D (f19, 5.0, false); ++  D (f19, 6.0, false); ++  D (f20, 4.0, false); ++  D (f20, 5.0, true); ++  D (f20, 6.0, true); ++  D (f21, 4.0, false); ++  D (f21, 5.0, true); ++  D (f21, 6.0, false); ++  D (f22, 4.0, true); ++  D (f22, 5.0, false); ++  D (f22, 6.0, true); ++  D (f23, 4.0, false); ++  D (f23, 5.0, false); ++  D (f23, 6.0, true); ++  D (f24, 4.0, true); ++  D (f24, 5.0, true); ++  D (f24, 6.0, false); ++} +diff --git a/gcc/testsuite/gcc.dg/pr94589-1.c b/gcc/testsuite/gcc.dg/pr94589-1.c +new file mode 100644 +index 000000000..de404ea82 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-1.c +@@ -0,0 +1,35 @@ ++/* PR tree-optimization/94589 */ ++/* { dg-do compile } */ ++/* { 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\\) (?:<|<=|==|!=|>|>=) \[45]" 14 "optimized" } } */ ++ ++#define A __attribute__((noipa)) ++A int f1 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 0; } ++A int f2 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 0; } ++A int f3 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > 0; } ++A int f4 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 0; } ++A int f5 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 0; } ++A int f6 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= 0; } ++A int f7 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == -1; } ++A int f8 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != -1; } ++A int f9 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > -1; } ++A int f10 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= -1; } ++A int f11 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 1; } ++A int f12 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 1; } ++A int f13 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 1; } ++A int f14 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 1; } ++A int f15 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 0; } ++A int f16 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 0; } ++A int f17 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > 0; } ++A int f18 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 0; } ++A int f19 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 0; } ++A int f20 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= 0; } ++A int f21 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == -1; } ++A int f22 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != -1; } ++A int f23 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > -1; } ++A int f24 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= -1; } ++A int f25 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 1; } ++A int f26 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 1; } ++A int f27 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 1; } ++A int f28 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 1; } +diff --git a/gcc/testsuite/gcc.dg/pr94589-2.c b/gcc/testsuite/gcc.dg/pr94589-2.c +new file mode 100644 +index 000000000..9481b764d +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-2.c +@@ -0,0 +1,35 @@ ++/* PR tree-optimization/94589 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -g0 -ffast-math -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 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 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 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; } ++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; } +diff --git a/gcc/testsuite/gcc.dg/pr94589-3.c b/gcc/testsuite/gcc.dg/pr94589-3.c +new file mode 100644 +index 000000000..df82fab73 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-3.c +@@ -0,0 +1,97 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 -g" } */ ++ ++#include "pr94589-1.c" ++ ++#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, 8, 0); ++  C (f1, 8, 8, 1); ++  C (f1, 9, 8, 0); ++  C (f2, 7, 8, 1); ++  C (f2, 8, 8, 0); ++  C (f2, 9, 8, 1); ++  C (f3, 7, 8, 0); ++  C (f3, 8, 8, 0); ++  C (f3, 9, 8, 1); ++  C (f4, 7, 8, 1); ++  C (f4, 8, 8, 0); ++  C (f4, 9, 8, 0); ++  C (f5, 7, 8, 0); ++  C (f5, 8, 8, 1); ++  C (f5, 9, 8, 1); ++  C (f6, 7, 8, 1); ++  C (f6, 8, 8, 1); ++  C (f6, 9, 8, 0); ++  C (f7, 7, 8, 1); ++  C (f7, 8, 8, 0); ++  C (f7, 9, 8, 0); ++  C (f8, 7, 8, 0); ++  C (f8, 8, 8, 1); ++  C (f8, 9, 8, 1); ++  C (f9, 7, 8, 0); ++  C (f9, 8, 8, 1); ++  C (f9, 9, 8, 1); ++  C (f10, 7, 8, 1); ++  C (f10, 8, 8, 0); ++  C (f10, 9, 8, 0); ++  C (f11, 7, 8, 0); ++  C (f11, 8, 8, 0); ++  C (f11, 9, 8, 1); ++  C (f12, 7, 8, 1); ++  C (f12, 8, 8, 1); ++  C (f12, 9, 8, 0); ++  C (f13, 7, 8, 1); ++  C (f13, 8, 8, 1); ++  C (f13, 9, 8, 0); ++  C (f14, 7, 8, 0); ++  C (f14, 8, 8, 0); ++  C (f14, 9, 8, 1); ++  D (f15, 4, 0); ++  D (f15, 5, 1); ++  D (f15, 6, 0); ++  D (f16, 4, 1); ++  D (f16, 5, 0); ++  D (f16, 6, 1); ++  D (f17, 4, 0); ++  D (f17, 5, 0); ++  D (f17, 6, 1); ++  D (f18, 4, 1); ++  D (f18, 5, 0); ++  D (f18, 6, 0); ++  D (f19, 4, 0); ++  D (f19, 5, 1); ++  D (f19, 6, 1); ++  D (f20, 4, 1); ++  D (f20, 5, 1); ++  D (f20, 6, 0); ++  D (f21, 4, 1); ++  D (f21, 5, 0); ++  D (f21, 6, 0); ++  D (f22, 4, 0); ++  D (f22, 5, 1); ++  D (f22, 6, 1); ++  D (f23, 4, 0); ++  D (f23, 5, 1); ++  D (f23, 6, 1); ++  D (f24, 4, 1); ++  D (f24, 5, 0); ++  D (f24, 6, 0); ++  D (f25, 4, 0); ++  D (f25, 5, 0); ++  D (f25, 6, 1); ++  D (f26, 4, 1); ++  D (f26, 5, 1); ++  D (f26, 6, 0); ++  D (f27, 4, 1); ++  D (f27, 5, 1); ++  D (f27, 6, 0); ++  D (f28, 4, 0); ++  D (f28, 5, 0); ++  D (f28, 6, 1); ++  return 0; ++} +diff --git a/gcc/testsuite/gcc.dg/pr94589-4.c b/gcc/testsuite/gcc.dg/pr94589-4.c +new file mode 100644 +index 000000000..b2557fb07 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-4.c +@@ -0,0 +1,97 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 -g -ffast-math" } */ ++ ++#include "pr94589-2.c" ++ ++#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 (f2, 7.0, 8.0, 1); ++  C (f2, 8.0, 8.0, 0); ++  C (f2, 9.0, 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 (f4, 7.0, 8.0, 1); ++  C (f4, 8.0, 8.0, 0); ++  C (f4, 9.0, 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 (f6, 7.0, 8.0, 1); ++  C (f6, 8.0, 8.0, 1); ++  C (f6, 9.0, 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 (f8, 7.0, 8.0, 0); ++  C (f8, 8.0, 8.0, 1); ++  C (f8, 9.0, 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 (f10, 7.0, 8.0, 1); ++  C (f10, 8.0, 8.0, 0); ++  C (f10, 9.0, 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 (f12, 7.0, 8.0, 1); ++  C (f12, 8.0, 8.0, 1); ++  C (f12, 9.0, 8.0, 0); ++  C (f13, 7.0, 8.0, 1); ++  C (f13, 8.0, 8.0, 1); ++  C (f13, 9.0, 8.0, 0); ++  C (f14, 7.0, 8.0, 0); ++  C (f14, 8.0, 8.0, 0); ++  C (f14, 9.0, 8.0, 1); ++  D (f15, 4.0, 0); ++  D (f15, 5.0, 1); ++  D (f15, 6.0, 0); ++  D (f16, 4.0, 1); ++  D (f16, 5.0, 0); ++  D (f16, 6.0, 1); ++  D (f17, 4.0, 0); ++  D (f17, 5.0, 0); ++  D (f17, 6.0, 1); ++  D (f18, 4.0, 1); ++  D (f18, 5.0, 0); ++  D (f18, 6.0, 0); ++  D (f19, 4.0, 0); ++  D (f19, 5.0, 1); ++  D (f19, 6.0, 1); ++  D (f20, 4.0, 1); ++  D (f20, 5.0, 1); ++  D (f20, 6.0, 0); ++  D (f21, 4.0, 1); ++  D (f21, 5.0, 0); ++  D (f21, 6.0, 0); ++  D (f22, 4.0, 0); ++  D (f22, 5.0, 1); ++  D (f22, 6.0, 1); ++  D (f23, 4.0, 0); ++  D (f23, 5.0, 1); ++  D (f23, 6.0, 1); ++  D (f24, 4.0, 1); ++  D (f24, 5.0, 0); ++  D (f24, 6.0, 0); ++  D (f25, 4.0, 0); ++  D (f25, 5.0, 0); ++  D (f25, 6.0, 1); ++  D (f26, 4.0, 1); ++  D (f26, 5.0, 1); ++  D (f26, 6.0, 0); ++  D (f27, 4.0, 1); ++  D (f27, 5.0, 1); ++  D (f27, 6.0, 0); ++  D (f28, 4.0, 0); ++  D (f28, 5.0, 0); ++  D (f28, 6.0, 1); ++  return 0; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index b9cd07a60..fca32222f 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -63,6 +63,8 @@ static bool abs_replacement (basic_block, basic_block, + 			     edge, edge, gimple *, tree, tree); + static bool xor_replacement (basic_block, basic_block, + 			     edge, edge, gimple *, tree, tree); ++static bool spaceship_replacement (basic_block, basic_block, ++				   edge, edge, gphi *, tree, tree); + static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, + 						      edge, edge, gimple *, + 						      tree, tree); +@@ -361,6 +363,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + 	    cfgchanged = true; + 	  else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + 	    cfgchanged = true; ++	  else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) ++	    cfgchanged = true; + 	} +     } +  +@@ -1753,6 +1757,426 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, +   return true; + } +  ++/* Return true if the only executable statement in BB is a GIMPLE_COND.  */ ++ ++static bool ++cond_only_block_p (basic_block bb) ++{ ++  /* BB must have no executable statements.  */ ++  gimple_stmt_iterator gsi = gsi_after_labels (bb); ++  if (phi_nodes (bb)) ++    return false; ++  while (!gsi_end_p (gsi)) ++    { ++      gimple *stmt = gsi_stmt (gsi); ++      if (is_gimple_debug (stmt)) ++	; ++      else if (gimple_code (stmt) == GIMPLE_NOP ++	       || gimple_code (stmt) == GIMPLE_PREDICT ++	       || gimple_code (stmt) == GIMPLE_COND) ++	; ++      else ++	return false; ++      gsi_next (&gsi); ++    } ++  return true; ++} ++ ++/* Attempt to optimize (x <=> y) cmp 0 and similar comparisons. ++   For strong ordering <=> try to match something like: ++    <bb 2> :  // cond3_bb (== cond2_bb) ++    if (x_4(D) != y_5(D)) ++      goto <bb 3>; [INV] ++    else ++      goto <bb 6>; [INV] ++ ++    <bb 3> :  // cond_bb ++    if (x_4(D) < y_5(D)) ++      goto <bb 6>; [INV] ++    else ++      goto <bb 4>; [INV] ++ ++    <bb 4> :  // middle_bb ++ ++    <bb 6> :  // phi_bb ++    # iftmp.0_2 = PHI <1(4), 0(2), -1(3)> ++    _1 = iftmp.0_2 == 0; ++ ++   and for partial ordering <=> something like: ++ ++    <bb 2> :  // cond3_bb ++    if (a_3(D) == b_5(D)) ++      goto <bb 6>; [50.00%] ++    else ++      goto <bb 3>; [50.00%] ++ ++    <bb 3> [local count: 536870913]:  // cond2_bb ++    if (a_3(D) < b_5(D)) ++      goto <bb 6>; [50.00%] ++    else ++      goto <bb 4>; [50.00%] ++ ++    <bb 4> [local count: 268435456]:  // cond_bb ++    if (a_3(D) > b_5(D)) ++      goto <bb 6>; [50.00%] ++    else ++      goto <bb 5>; [50.00%] ++ ++    <bb 5> [local count: 134217728]:  // middle_bb ++ ++    <bb 6> [local count: 1073741824]:  // phi_bb ++    # SR.27_4 = PHI <0(2), -1(3), 1(4), 2(5)> ++    _2 = SR.27_4 > 0;  */ ++ ++static bool ++spaceship_replacement (basic_block cond_bb, basic_block middle_bb, ++		       edge e0, edge e1, gphi *phi, ++		       tree arg0, tree arg1) ++{ ++  if (!INTEGRAL_TYPE_P (TREE_TYPE (PHI_RESULT (phi))) ++      || TYPE_UNSIGNED (TREE_TYPE (PHI_RESULT (phi))) ++      || !tree_fits_shwi_p (arg0) ++      || !tree_fits_shwi_p (arg1) ++      || !IN_RANGE (tree_to_shwi (arg0), -1, 2) ++      || !IN_RANGE (tree_to_shwi (arg1), -1, 2)) ++    return false; ++ ++  basic_block phi_bb = gimple_bb (phi); ++  gcc_assert (phi_bb == e0->dest && phi_bb == e1->dest); ++  if (!IN_RANGE (EDGE_COUNT (phi_bb->preds), 3, 4)) ++    return false; ++ ++  use_operand_p use_p; ++  gimple *use_stmt; ++  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))) ++    return false; ++  if (!single_imm_use (PHI_RESULT (phi), &use_p, &use_stmt)) ++    return false; ++  enum tree_code cmp; ++  tree lhs, rhs; ++  if (gimple_code (use_stmt) == GIMPLE_COND) ++    { ++      cmp = gimple_cond_code (use_stmt); ++      lhs = gimple_cond_lhs (use_stmt); ++      rhs = gimple_cond_rhs (use_stmt); ++    } ++  else if (is_gimple_assign (use_stmt)) ++    { ++      if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS) ++	{ ++	  cmp = gimple_assign_rhs_code (use_stmt); ++	  lhs = gimple_assign_rhs1 (use_stmt); ++	  rhs = gimple_assign_rhs2 (use_stmt); ++	} ++      else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR) ++	{ ++	  tree cond = gimple_assign_rhs1 (use_stmt); ++	  if (!COMPARISON_CLASS_P (cond)) ++	    return false; ++	  cmp = TREE_CODE (cond); ++	  lhs = TREE_OPERAND (cond, 0); ++	  rhs = TREE_OPERAND (cond, 1); ++	} ++      else ++	return false; ++    } ++  else ++    return false; ++  switch (cmp) ++    { ++    case EQ_EXPR: ++    case NE_EXPR: ++    case LT_EXPR: ++    case GT_EXPR: ++    case LE_EXPR: ++    case GE_EXPR: ++      break; ++    default: ++      return false; ++    } ++  if (lhs != PHI_RESULT (phi) ++      || !tree_fits_shwi_p (rhs) ++      || !IN_RANGE (tree_to_shwi (rhs), -1, 1)) ++    return false; ++ ++  if (!empty_block_p (middle_bb)) ++    return false; ++ ++  gcond *cond1 = as_a <gcond *> (last_stmt (cond_bb)); ++  enum tree_code cmp1 = gimple_cond_code (cond1); ++  if (cmp1 != LT_EXPR && cmp1 != GT_EXPR) ++    return false; ++  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)) ++    return false; ++ ++  if (!single_pred_p (cond_bb) || !cond_only_block_p (cond_bb)) ++    return false; ++ ++  basic_block cond2_bb = single_pred (cond_bb); ++  if (EDGE_COUNT (cond2_bb->succs) != 2) ++    return false; ++  edge cond2_phi_edge; ++  if (EDGE_SUCC (cond2_bb, 0)->dest == cond_bb) ++    { ++      if (EDGE_SUCC (cond2_bb, 1)->dest != phi_bb) ++	return false; ++      cond2_phi_edge = EDGE_SUCC (cond2_bb, 1); ++    } ++  else if (EDGE_SUCC (cond2_bb, 0)->dest != phi_bb) ++    return false; ++  else ++    cond2_phi_edge = EDGE_SUCC (cond2_bb, 0); ++  tree arg2 = gimple_phi_arg_def (phi, cond2_phi_edge->dest_idx); ++  if (!tree_fits_shwi_p (arg2)) ++    return false; ++  gimple *cond2 = last_stmt (cond2_bb); ++  if (cond2 == NULL || gimple_code (cond2) != GIMPLE_COND) ++    return false; ++  enum tree_code cmp2 = gimple_cond_code (cond2); ++  tree lhs2 = gimple_cond_lhs (cond2); ++  tree rhs2 = gimple_cond_rhs (cond2); ++  if (lhs2 == lhs1) ++    { ++      if (!operand_equal_p (rhs2, rhs1, 0)) ++	return false; ++    } ++  else if (lhs2 == rhs1) ++    { ++      if (rhs2 != lhs1) ++	return false; ++    } ++  else ++    return false; ++ ++  tree arg3 = arg2; ++  basic_block cond3_bb = cond2_bb; ++  edge cond3_phi_edge = cond2_phi_edge; ++  gimple *cond3 = cond2; ++  enum tree_code cmp3 = cmp2; ++  tree lhs3 = lhs2; ++  tree rhs3 = rhs2; ++  if (EDGE_COUNT (phi_bb->preds) == 4) ++    { ++      if (absu_hwi (tree_to_shwi (arg2)) != 1) ++	return false; ++      if (e1->flags & EDGE_TRUE_VALUE) ++	{ ++	  if (tree_to_shwi (arg0) != 2 ++	      || absu_hwi (tree_to_shwi (arg1)) != 1 ++	      || wi::to_widest (arg1) == wi::to_widest (arg2)) ++	    return false; ++	} ++      else if (tree_to_shwi (arg1) != 2 ++	       || absu_hwi (tree_to_shwi (arg0)) != 1 ++	       || wi::to_widest (arg0) == wi::to_widest (arg1)) ++	return false; ++      if (cmp2 != LT_EXPR && cmp2 != GT_EXPR) ++	return false; ++      /* if (x < y) goto phi_bb; else fallthru; ++	 if (x > y) goto phi_bb; else fallthru; ++	 bbx:; ++	 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 second goto phi_bb is not the true edge, it is not.  */ ++      if ((lhs2 == lhs1) ++	  ^ (cmp2 == cmp1) ++	  ^ ((e1->flags & EDGE_TRUE_VALUE) != 0)) ++	return false; ++      if ((cond2_phi_edge->flags & EDGE_TRUE_VALUE) == 0) ++	return false; ++      if (!single_pred_p (cond2_bb) || !cond_only_block_p (cond2_bb)) ++	return false; ++      cond3_bb = single_pred (cond2_bb); ++      if (EDGE_COUNT (cond2_bb->succs) != 2) ++	return false; ++      if (EDGE_SUCC (cond3_bb, 0)->dest == cond2_bb) ++	{ ++	  if (EDGE_SUCC (cond3_bb, 1)->dest != phi_bb) ++	    return false; ++	  cond3_phi_edge = EDGE_SUCC (cond3_bb, 1); ++	} ++      else if (EDGE_SUCC (cond3_bb, 0)->dest != phi_bb) ++	return false; ++      else ++	cond3_phi_edge = EDGE_SUCC (cond3_bb, 0); ++      arg3 = gimple_phi_arg_def (phi, cond3_phi_edge->dest_idx); ++      cond3 = last_stmt (cond3_bb); ++      if (cond3 == NULL || gimple_code (cond3) != GIMPLE_COND) ++	return false; ++      cmp3 = gimple_cond_code (cond3); ++      lhs3 = gimple_cond_lhs (cond3); ++      rhs3 = gimple_cond_rhs (cond3); ++      if (lhs3 == lhs1) ++	{ ++	  if (!operand_equal_p (rhs3, rhs1, 0)) ++	    return false; ++	} ++      else if (lhs3 == rhs1) ++	{ ++	  if (rhs3 != lhs1) ++	    return false; ++	} ++      else ++	return false; ++    } ++  else if (absu_hwi (tree_to_shwi (arg0)) != 1 ++	   || absu_hwi (tree_to_shwi (arg1)) != 1 ++	   || wi::to_widest (arg0) == wi::to_widest (arg1)) ++    return false; ++ ++  if (!integer_zerop (arg3) || (cmp3 != EQ_EXPR && cmp3 != NE_EXPR)) ++    return false; ++  if ((cond3_phi_edge->flags & (cmp3 == EQ_EXPR ++				? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) == 0) ++    return false; ++ ++  /* lhs1 one_cmp rhs1 results in PHI_RESULT (phi) of 1.  */ ++  enum tree_code one_cmp; ++  if ((cmp1 == LT_EXPR) ++      ^ (!integer_onep ((e1->flags & EDGE_TRUE_VALUE) ? arg1 : arg0))) ++    one_cmp = LT_EXPR; ++  else ++    one_cmp = GT_EXPR; ++ ++  enum tree_code res_cmp; ++  switch (cmp) ++    { ++    case EQ_EXPR: ++      if (integer_zerop (rhs)) ++	res_cmp = EQ_EXPR; ++      else if (integer_minus_onep (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR; ++      else if (integer_onep (rhs)) ++	res_cmp = one_cmp; ++      else ++	return false; ++      break; ++    case NE_EXPR: ++      if (integer_zerop (rhs)) ++	res_cmp = NE_EXPR; ++      else if (integer_minus_onep (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++      else if (integer_onep (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR; ++      else ++	return false; ++      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; ++      else ++	return false; ++      break; ++    case LE_EXPR: ++      if (integer_zerop (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR; ++      else if (integer_minus_onep (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR; ++      else ++	return false; ++      break; ++    case GT_EXPR: ++      if (integer_minus_onep (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++      else if (integer_zerop (rhs)) ++	res_cmp = one_cmp; ++      else ++	return false; ++      break; ++    case GE_EXPR: ++      if (integer_zerop (rhs)) ++	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++      else if (integer_onep (rhs)) ++	res_cmp = one_cmp; ++      else ++	return false; ++      break; ++    default: ++      gcc_unreachable (); ++    } ++ ++  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); ++    } ++  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); ++    } ++  else ++    { ++      tree cond = build2 (res_cmp, TREE_TYPE (gimple_assign_rhs1 (use_stmt)), ++			  lhs1, rhs1); ++      gimple_assign_set_rhs1 (use_stmt, cond); ++    } ++  update_stmt (use_stmt); ++ ++  if (MAY_HAVE_DEBUG_BIND_STMTS) ++    { ++      use_operand_p use_p; ++      imm_use_iterator iter; ++      bool has_debug_uses = false; ++      FOR_EACH_IMM_USE_FAST (use_p, iter, PHI_RESULT (phi)) ++	{ ++	  gimple *use_stmt = USE_STMT (use_p); ++	  gcc_assert (is_gimple_debug (use_stmt)); ++	  has_debug_uses = true; ++	  break; ++	} ++ ++      if (has_debug_uses) ++	{ ++	  /* If there are debug uses, emit something like: ++	     # DEBUG D#1 => i_2(D) > j_3(D) ? 1 : -1 ++	     # 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.  */ ++	  gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (phi)); ++	  tree type = TREE_TYPE (PHI_RESULT (phi)); ++	  tree temp1 = make_node (DEBUG_EXPR_DECL); ++	  DECL_ARTIFICIAL (temp1) = 1; ++	  TREE_TYPE (temp1) = type; ++	  SET_DECL_MODE (temp1, TYPE_MODE (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)); ++	  gimple *g = gimple_build_debug_bind (temp1, t, phi); ++	  gsi_insert_before (&gsi, g, GSI_SAME_STMT); ++	  tree temp2 = make_node (DEBUG_EXPR_DECL); ++	  DECL_ARTIFICIAL (temp2) = 1; ++	  TREE_TYPE (temp2) = type; ++	  SET_DECL_MODE (temp2, TYPE_MODE (type)); ++	  t = build2 (EQ_EXPR, boolean_type_node, lhs1, rhs2); ++	  t = build3 (COND_EXPR, type, t, build_zero_cst (type), temp1); ++	  g = gimple_build_debug_bind (temp2, t, phi); ++	  gsi_insert_before (&gsi, g, GSI_SAME_STMT); ++	  replace_uses_by (PHI_RESULT (phi), temp2); ++	} ++    } ++ ++  gimple_stmt_iterator psi = gsi_for_stmt (phi); ++  remove_phi_node (&psi, true); ++ ++  return true; ++} ++ + /* Convert +  +    <bb 2> +--  +2.27.0.windows.1 +  | 
