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