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
>

Reply via email to