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; }
