On Wed, Jul 1, 2026 at 7:12 AM Andrew Pinski <[email protected]> wrote: > > 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.
OK with the typo fixes. I wonder how much of forwprop combine_cond_expr_cond dispatch to GENERIC folding still results in sth that match cannot handle? Richard. > 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 >
