Re: [PATCH 1/2] match/fold: Add support for NE, XOR, and EQ to combine_comparisons [PR107881]
Richard Biener <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAFiYyc3=za1_KfmHzyScWHtLiOD2Kfy97tDpd33GRrmqCw056Q@mail.gmail.com> |
On Sun, Aug 16, 2026 at 4:12 AM Andrea Pinski <[email protected]> wrote: > > This adds support for !=, ^ and == to combine_comparisons and > uses combine_comparisons in match for those cases instead of what > was previously there. This allows for floating point comparisons to > be merged in some more cases. And simplifies the match code to read. > Also moves up the match pattern that uses combine_comparisons to > above the other comparisons combines so it is matched first. > > Bootstrapped and tested on x86_64-linux-gnu. Nice. OK. THanks, Richard. > PR tree-optimization/107881 > > gcc/ChangeLog: > > * fold-const.cc (combine_comparisons): Add support for > NE/XOR and EQ. > * match.pd (`(a CMP1 b) OP (a CMP2 b)`): Move > above others and add NE, XOR and EQ to the list of OPs. > (`(a CMP1 b) ^ (a CMP2 b)`): Remove. > (`(a CMP1 b) == (a CMP2 b)`): Remove. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/cmpeq-5.c: New test. > * gcc.dg/tree-ssa/cmpxor-2.c: New test. > > Signed-off-by: Andrea Pinski <[email protected]> > --- > gcc/fold-const.cc | 9 ++++ > gcc/match.pd | 68 +++++++----------------- > gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c | 51 ++++++++++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c | 51 ++++++++++++++++++ > 4 files changed, 131 insertions(+), 48 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c > > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc > index 420e3185a2a..dd6ce48f89a 100644 > --- a/gcc/fold-const.cc > +++ b/gcc/fold-const.cc > @@ -2964,6 +2964,15 @@ combine_comparisons (enum tree_code code, enum tree_code lcode, > compcode = lcompcode | rcompcode; > break; > > + case BIT_XOR_EXPR: > + case NE_EXPR: > + compcode = lcompcode ^ rcompcode; > + break; > + > + case EQ_EXPR: > + compcode = (~(lcompcode ^ rcompcode)) & 0xf; > + break; > + > default: > return ERROR_MARK; > } > diff --git a/gcc/match.pd b/gcc/match.pd > index 02684d8a302..f8251885a7c 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -3619,6 +3619,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1))) > (gt @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); })))) > > +/* Optimize (a CMP b) &| (a CMP b) > + using the helper combine_comparisons function. */ > +(for bitop (bit_and bit_ior bit_xor ne eq) > + (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))))))))) > + > /* Convert (X == CST1) && ((other)X OP2 CST2) to a known value > based on CST1 OP2 CST2. Similarly for (X != CST1). */ > /* Convert (X == Y) && (X OP2 Y) to a known value if X is an integral type. > @@ -3904,54 +3924,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > { constant_boolean_node (true, type); }) > )))))) > > -/* Optimize (a CMP b) ^ (a CMP b) */ > -/* Optimize (a CMP b) != (a CMP b) */ > -(for op (bit_xor ne) > - (for cmp1 (lt lt lt le le le) > - cmp2 (gt eq ne ge eq ne) > - rcmp (ne le gt ne lt ge) > - (simplify > - (op:c (cmp1:c @0 @1) (cmp2 @0 @1)) > - (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) > - || POINTER_TYPE_P (TREE_TYPE (@0)) > - || ((VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1)) > - || VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (@1))) > - && expand_vec_cmp_expr_p (TREE_TYPE (@0), type, rcmp))) > - (rcmp @0 @1))))) > - > -/* Optimize (a CMP b) == (a CMP b) */ > -(for cmp1 (lt lt lt le le le) > - cmp2 (gt eq ne ge eq ne) > - rcmp (eq gt le eq ge lt) > - (simplify > - (eq:c (cmp1:c @0 @1) (cmp2 @0 @1)) > - (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) > - || POINTER_TYPE_P (TREE_TYPE (@0)) > - || ((VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1)) > - || VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (@1))) > - && 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/gcc.dg/tree-ssa/cmpeq-5.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c > new file mode 100644 > index 00000000000..16dc35ca39e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c > @@ -0,0 +1,51 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */ > +/* PR tree-optimization/107881 */ > + > +_Bool ltgt_eq(float a, float b) > +{ > + _Bool c = a < b; > + _Bool d = a > b; > + return c == d; // a u== b > +} > +/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. u== b_\[0-9\]+.D.|b_\[0-9\]+.D. u== a_\[0-9\]+.D." "optimized" } } */ > + > +_Bool lteq_eq(float x, float y) > +{ > + _Bool c = x < y; > + _Bool d = x == y; > + return c == d; // x u> y > +} > +/* { dg-final { scan-tree-dump "x_\[0-9\]+.D. u> y_\[0-9\]+.D.|y_\[0-9\]+.D. u< x_\[0-9\]+.D." "optimized" } } */ > + > +_Bool ltne_eq(float z, float w) > +{ > + _Bool c = z < w; > + _Bool d = z != w; > + return c == d; // z <= w > +} > +/* { dg-final { scan-tree-dump "z_\[0-9\]+.D. <= w_\[0-9\]+.D.|w_\[0-9\]+.D. >= y_\[0-9\]+.D." "optimized" } } */ > + > +_Bool lege_eq(float i, float j) > +{ > + _Bool c = i <= j; > + _Bool d = i >= j; > + return c == d; // i u== j > +} > +/* { dg-final { scan-tree-dump "i_\[0-9\]+.D. u== j_\[0-9\]+.D.|j_\[0-9\]+.D. u== i_\[0-9\]+.D." "optimized" } } */ > + > +_Bool leeq_eq(float k, float l) > +{ > + _Bool c = k <= l; > + _Bool d = k == l; > + return c == d; // k u>= l > +} > +/* { dg-final { scan-tree-dump "k_\[0-9\]+.D. u>= l_\[0-9\]+.D.|l_\[0-9\]+.D. u<= k_\[0-9\]+.D." "optimized" } } */ > + > +_Bool lene_eq(float m, float n) > +{ > + _Bool c = m <= n; > + _Bool d = m != n; > + return c == d; // m < n > +} > +/* { dg-final { scan-tree-dump "m_\[0-9\]+.D. < n_\[0-9\]+.D.|n_\[0-9\]+.D. > m_\[0-9\]+.D." "optimized" } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c > new file mode 100644 > index 00000000000..00fa7120237 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c > @@ -0,0 +1,51 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */ > +/* PR tree-optimization/107881 */ > + > +_Bool ltgtxor(float a, float b) > +{ > + _Bool c = a < b; > + _Bool d = a > b; > + return c ^ d; // a <> b > +} > +/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. <> b_\[0-9\]+.D.|b_\[0-9\]+.D. <> a_\[0-9\]+.D." "optimized" } } */ > + > +_Bool lteqxor(float x, float y) > +{ > + _Bool c = x < y; > + _Bool d = x == y; > + return c ^ d; // x <= y (basically | here) > +} > +/* { dg-final { scan-tree-dump "x_\[0-9\]+.D. <= y_\[0-9\]+.D.|y_\[0-9\]+.D. >= x_\[0-9\]+.D." "optimized" } } */ > + > +_Bool ltnexor(float z, float w) > +{ > + _Bool c = z < w; > + _Bool d = z != w; > + return c ^ d; // z u> w > +} > +/* { dg-final { scan-tree-dump "z_\[0-9\]+.D. u> w_\[0-9\]+.D.|w_\[0-9\]+.D. u< y_\[0-9\]+.D." "optimized" } } */ > + > +_Bool legexor(float i, float j) > +{ > + _Bool c = i <= j; > + _Bool d = i >= j; > + return c ^ d; // i <> j > +} > +/* { dg-final { scan-tree-dump "i_\[0-9\]+.D. <> j_\[0-9\]+.D.|j_\[0-9\]+.D. <> i_\[0-9\]+.D." "optimized" } } */ > + > +_Bool leeqxor(float k, float l) > +{ > + _Bool c = k <= l; > + _Bool d = k == l; > + return c ^ d; // k < l > +} > +/* { dg-final { scan-tree-dump "k_\[0-9\]+.D. < l_\[0-9\]+.D.|l_\[0-9\]+.D. > k_\[0-9\]+.D." "optimized" } } */ > + > +_Bool lenexor(float m, float n) > +{ > + _Bool c = m <= n; > + _Bool d = m != n; > + return c ^ d; // m u>= n > +} > +/* { dg-final { scan-tree-dump "m_\[0-9\]+.D. u>= n_\[0-9\]+.D.|n_\[0-9\]+.D. u<= m_\[0-9\]+.D." "optimized" } } */ > -- > 2.43.0 >