https://gcc.gnu.org/g:ea8c74c074925b93f013519a63e3518e0c448b85

commit r17-2129-gea8c74c074925b93f013519a63e3518e0c448b85
Author: Andrew Pinski <[email protected]>
Date:   Tue Jun 30 12:13:05 2026 -0700

    match: Simplify `(a CMP1 b) AND/IOR (a CMP2 b)` [PR126042]
    
    This finishes up simplifications of most comparisons
    outside of reassociation. Including but not limited to
    many floating point comparisons.
    Instead of redoing what is done in fold-cost.cc's combine_comparisons,
    this reuses combine_comparisons to find the new CMP.
    
    In the case of `-fno-trapping-math`, this allows to optimize `<=>`
    which it was not before.
    
    Changes since v1:
    * v2: Fix some typos. Add a C testcase.
    
    Bootstrapped and tested on x86_64-linux-gnu.
    
            PR tree-optimization/106164
            PR tree-optimization/126042
            PR tree-optimization/94589
    
    gcc/ChangeLog:
    
            * fold-const.cc (combine_comparisons): Split into
            2 versions. Also handle BIT_AND_EXPR and BIT_IOR_EXPR.
            * fold-const.h (combine_comparisons): New declaration.
            * match.pd (`(a CMP1 b) BITOP (a CMP2 b)`): New pattern.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/opt/pr94589-5a.C: New test.
            * gcc.dg/pr94589-5.c: Explictly enable -ftrapping-math.
            * gcc.dg/pr94589-5a.c: New test.
    
    Signed-off-by: Andrew Pinski <[email protected]>

Diff:
---
 gcc/fold-const.cc                     | 65 ++++++++++++++++++++++++-----------
 gcc/fold-const.h                      |  2 ++
 gcc/match.pd                          | 20 +++++++++++
 gcc/testsuite/g++.dg/opt/pr94589-5a.C | 27 +++++++++++++++
 gcc/testsuite/gcc.dg/pr94589-5.c      |  2 +-
 gcc/testsuite/gcc.dg/pr94589-5a.c     | 55 +++++++++++++++++++++++++++++
 6 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 11d1129f1253..1d0ed62a82fe 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -2935,35 +2935,37 @@ inverse_conditions_p (const_tree cond1, const_tree 
cond2)
                              TREE_OPERAND (cond2, 1), 0));
 }
 
-/* Return a tree for the comparison which is the combination of
+/* Return a code for the comparison which is the combination of
    doing the AND or OR (depending on CODE) of the two operations LCODE
    and RCODE on the identical operands LL_ARG and LR_ARG.  Take into account
-   the possibility of trapping if the mode has NaNs, and return NULL_TREE
-   if this makes the transformation invalid.  */
+   the possibility of trapping if the mode has NaNs, and return ERROR_MARK
+   if this makes the transformation invalid. If the resulting code is
+   INTEGER_CST, then *RES will be set to a non-NULL CONSTANT.  */
 
-tree
-combine_comparisons (location_t loc,
-                    enum tree_code code, enum tree_code lcode,
-                    enum tree_code rcode, tree truth_type,
-                    tree ll_arg, tree lr_arg)
+enum tree_code
+combine_comparisons (enum tree_code code, enum tree_code lcode,
+                      enum tree_code rcode, tree truth_type,
+                      bool honor_nans, tree *res)
 {
-  bool honor_nans = HONOR_NANS (ll_arg);
   enum comparison_code lcompcode = comparison_to_compcode (lcode);
   enum comparison_code rcompcode = comparison_to_compcode (rcode);
   int compcode;
+  *res = NULL_TREE;
 
   switch (code)
     {
     case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR:
+    case BIT_AND_EXPR:
       compcode = lcompcode & rcompcode;
       break;
 
     case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR:
+    case BIT_IOR_EXPR:
       compcode = lcompcode | rcompcode;
       break;
 
     default:
-      return NULL_TREE;
+      return ERROR_MARK;
     }
 
   if (!honor_nans)
@@ -3004,24 +3006,45 @@ combine_comparisons (location_t loc,
           trapped, we may now generate a spurious trap.  */
        if (rtrap && !ltrap
            && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR))
-         return NULL_TREE;
+         return ERROR_MARK;
 
        /* If we changed the conditions that cause a trap, we lose.  */
        if ((ltrap || rtrap) != trap)
-         return NULL_TREE;
+         return ERROR_MARK;
       }
 
-  if (compcode == COMPCODE_TRUE)
-    return constant_boolean_node (true, truth_type);
-  else if (compcode == COMPCODE_FALSE)
-    return constant_boolean_node (false, truth_type);
-  else
+  if (compcode == COMPCODE_TRUE || compcode == COMPCODE_FALSE)
     {
-      enum tree_code tcode;
-
-      tcode = compcode_to_comparison ((enum comparison_code) compcode);
-      return fold_build2_loc (loc, tcode, truth_type, ll_arg, lr_arg);
+      *res = constant_boolean_node (compcode == COMPCODE_TRUE, truth_type);
+      return INTEGER_CST;
     }
+  else
+    return compcode_to_comparison ((enum comparison_code) compcode);
+}
+
+/* Return a tree for the comparison which is the combination of
+   doing the AND or OR (depending on CODE) of the two operations LCODE
+   and RCODE on the identical operands LL_ARG and LR_ARG.  Take into account
+   the possibility of trapping if the mode has NaNs, and return NULL_TREE
+   if this makes the transformation invalid.  */
+
+tree
+combine_comparisons (location_t loc,
+                    enum tree_code code, enum tree_code lcode,
+                    enum tree_code rcode, tree truth_type,
+                    tree ll_arg, tree lr_arg)
+{
+  bool honor_nans = HONOR_NANS (ll_arg);
+  tree_code rescode;
+  tree res;
+  rescode = combine_comparisons (code, lcode, rcode, truth_type,
+                                honor_nans, &res);
+  if (rescode == ERROR_MARK)
+    return NULL_TREE;
+  if (rescode == INTEGER_CST)
+    return res;
+
+  return fold_build2_loc (loc, rescode, truth_type, ll_arg, lr_arg);
 }
 
 /* Return nonzero if two operands (typically of the same tree node)
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 57d32b1b6ca2..8c0c3edba178 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -175,6 +175,8 @@ extern bool fold_real_zero_addition_p (const_tree, 
const_tree, const_tree,
                                       int);
 extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
                                 enum tree_code, tree, tree, tree);
+extern tree_code combine_comparisons (enum tree_code, enum tree_code,
+                                     enum tree_code, tree, bool, tree*);
 extern void debug_fold_checksum (const_tree);
 extern bool may_negate_without_overflow_p (const_tree);
 #define round_up(T,N) round_up_loc (UNKNOWN_LOCATION, T, N)
diff --git a/gcc/match.pd b/gcc/match.pd
index 817a52499128..a4a1ac94860a 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3784,6 +3784,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && expand_vec_cmp_expr_p (TREE_TYPE (@0), type,  rcmp)))
     (rcmp @0 @1))))
 
+/* Optimize (a CMP b) &| (a CMP b)
+   using the helper combine_comparisons function.  */
+(for bitop (bit_and bit_ior)
+ (for cmp1 (tcc_comparison)
+  (for cmp2 (tcc_comparison)
+   (for rcmp (tcc_comparison)
+    (simplify
+     (bitop (cmp1 @0 @1) (cmp2 @0 @1))
+     (with {
+       tree_code rescode;
+       tree res;
+       bool honor_nans = HONOR_NANS (@0);
+       rescode = combine_comparisons (bitop, cmp1, cmp2,
+                                     type, honor_nans, &res);
+      }
+      (if (rescode == INTEGER_CST)
+       { res; }
+       (if (rescode == rcmp)
+        (rcmp @0 @1)))))))))
+
 /* (type)([0,1]@a != 0) -> (type)a
    (type)([0,1]@a == 1) -> (type)a
    (type)([0,1]@a == 0) -> a ^ 1
diff --git a/gcc/testsuite/g++.dg/opt/pr94589-5a.C 
b/gcc/testsuite/g++.dg/opt/pr94589-5a.C
new file mode 100644
index 000000000000..d1c9b56b4140
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr94589-5a.C
@@ -0,0 +1,27 @@
+// PR tree-optimization/94589
+// { dg-do compile { target c++20 } }
+// { dg-require-effective-target inf }
+// { dg-options "-O2 -g0 -fdump-tree-optimized -fno-trapping-math" }
+// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) 
(?:<|<=|>|>=|u>=|u<=) \[ij]_\[0-9]+\\(D\\)" 8 "optimized" } }
+// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=|u>=|u<=) 
5\\.0" 8 "optimized" } }
+// { dg-final { scan-tree-dump-not " if " "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/gcc.dg/pr94589-5.c b/gcc/testsuite/gcc.dg/pr94589-5.c
index 65dfd057db5e..144ad6e693fb 100644
--- a/gcc/testsuite/gcc.dg/pr94589-5.c
+++ b/gcc/testsuite/gcc.dg/pr94589-5.c
@@ -1,6 +1,6 @@
 /* PR tree-optimization/94589 */
 /* { dg-do compile { target inf } } */
-/* { dg-options "-O2 -g0 -fdump-tree-optimized" } */
+/* { dg-options "-O2 -g0 -fdump-tree-optimized -ftrapping-math" } */
 /* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|>|>=) 
\[ij]_\[0-9]+\\(D\\)" 24 "optimized" } } */
 /* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=) 5\\.0" 24 
"optimized" } } */
 
diff --git a/gcc/testsuite/gcc.dg/pr94589-5a.c 
b/gcc/testsuite/gcc.dg/pr94589-5a.c
new file mode 100644
index 000000000000..f96e72786b2d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr94589-5a.c
@@ -0,0 +1,55 @@
+/* PR tree-optimization/94589 */
+/* { dg-do compile { target inf } } */
+/* { dg-options "-O2 -g0 -fdump-tree-optimized -fno-trapping-math" } */
+/* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) 
(?:<|<=|>|>=|u>=|u<=) \[ij]_\[0-9]+\\(D\\)" 24 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=|u>=|u<=) 
5\\.0" 24 "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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; 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 = -128; return c >= 1; }
+A signed char f31 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f < 0; }
+A signed char f32 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f > 0; }
+A signed char f33 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f <= 0; }
+A signed char f34 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f >= 0; }
+A signed char f35 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f == 1; }
+A signed char f36 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f != 1; }
+A signed char f37 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f < 1; }
+A signed char f38 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f >= 1; }
+A signed char f39 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f == -1; }
+A signed char f40 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f != -1; }
+A signed char f41 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f > -1; }
+A signed char f42 (double i, double j) { signed char c; if (i == j) c = 0; 
else if (i < j) c = -1; else if (i > j) c = 1; else c = -128; unsigned char d = 
c; unsigned char e = -d; signed char f = e; return f <= -1; }
+A signed char f45 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f < 0; }
+A signed char f46 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f > 0; }
+A signed char f47 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f <= 0; }
+A signed char f48 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f >= 0; }
+A signed char f49 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f == 1; }
+A signed char f50 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f != 1; }
+A signed char f51 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f < 1; }
+A signed char f52 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f >= 1; }
+A signed char f53 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f == -1; }
+A signed char f54 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f != -1; }
+A signed char f55 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f > -1; }
+A signed char f56 (double i) { signed char c; if (i == 5.0) c = 0; else if (i 
< 5.0) c = -1; else if (i > 5.0) c = 1; else c = -128; unsigned char d = c; 
unsigned char e = -d; signed char f = e; return f <= -1; }

Reply via email to