This finishes up simplifications of most comparisons
outside of reassiocation. Including but not limited to
many floating point comparisons.
Instead of Redoig 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.

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.

Signed-off-by: Andrew Pinski <[email protected]>
---
 gcc/fold-const.cc                     | 65 ++++++++++++++++++---------
 gcc/fold-const.h                      |  2 +
 gcc/match.pd                          | 20 +++++++++
 gcc/testsuite/g++.dg/opt/pr94589-5a.C | 27 +++++++++++
 4 files changed, 93 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-5a.C

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 11d1129f125..899212bfdff 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 coide 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 57d32b1b6ca..8c0c3edba17 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 ddf3b61638c..87695d9d667 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 00000000000..d1c9b56b414
--- /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; }
-- 
2.43.0

Reply via email to