On Wed, Jun 12, 2024 at 6:39 AM Andrew Pinski <quic_apin...@quicinc.com> wrote: > > As mentioned by Jeff in r15-831-g05daf617ea22e1d818295ed2d037456937e23530, we > don't handle > `(X | Y) & ~Y` -> `X & ~Y` on the gimple level when there are some different > signed > (but same precision) types dealing with matching `~Y` with the `Y` part. This > improves both gimple_bitwise_equal_p and gimple_bitwise_inverted_equal_p to > be able to say `(truncate)a` and `(truncate)a` are bitwise_equal and > that `~(truncate)a` and `(truncate)a` are bitwise_invert_equal. > > Bootstrapped and tested on x86_64-linux-gnu with no regressions.
OK. Richard. > PR tree-optimization/115449 > > gcc/ChangeLog: > > * gimple-match-head.cc (gimple_maybe_truncate): New declaration. > (gimple_bitwise_equal_p): Match truncations that differ only > in types with the same precision. > (gimple_bitwise_inverted_equal_p): For matching after bit_not_with_nop > call gimple_bitwise_equal_p. > * match.pd (maybe_truncate): New match pattern. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/bitops-10.c: New test. > > Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com> > --- > gcc/gimple-match-head.cc | 17 +++++------- > gcc/match.pd | 7 +++++ > gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c | 34 +++++++++++++++++++++++ > 3 files changed, 48 insertions(+), 10 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c > > diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc > index e26fa0860ee..924d3f1e710 100644 > --- a/gcc/gimple-match-head.cc > +++ b/gcc/gimple-match-head.cc > @@ -243,6 +243,7 @@ optimize_successive_divisions_p (tree divisor, tree > inner_div) > gimple_bitwise_equal_p (expr1, expr2, valueize) > > bool gimple_nop_convert (tree, tree *, tree (*) (tree)); > +bool gimple_maybe_truncate (tree, tree *, tree (*) (tree)); > > /* Helper function for bitwise_equal_p macro. */ > > @@ -271,6 +272,10 @@ gimple_bitwise_equal_p (tree expr1, tree expr2, tree > (*valueize) (tree)) > } > if (expr2 != expr4 && operand_equal_p (expr1, expr4, 0)) > return true; > + if (gimple_maybe_truncate (expr3, &expr3, valueize) > + && gimple_maybe_truncate (expr4, &expr4, valueize) > + && operand_equal_p (expr3, expr4, 0)) > + return true; > return false; > } > > @@ -318,21 +323,13 @@ gimple_bitwise_inverted_equal_p (tree expr1, tree > expr2, bool &wascmp, tree (*va > /* Try if EXPR1 was defined as ~EXPR2. */ > if (gimple_bit_not_with_nop (expr1, &other, valueize)) > { > - if (operand_equal_p (other, expr2, 0)) > - return true; > - tree expr4; > - if (gimple_nop_convert (expr2, &expr4, valueize) > - && operand_equal_p (other, expr4, 0)) > + if (gimple_bitwise_equal_p (other, expr2, valueize)) > return true; > } > /* Try if EXPR2 was defined as ~EXPR1. */ > if (gimple_bit_not_with_nop (expr2, &other, valueize)) > { > - if (operand_equal_p (other, expr1, 0)) > - return true; > - tree expr3; > - if (gimple_nop_convert (expr1, &expr3, valueize) > - && operand_equal_p (other, expr3, 0)) > + if (gimple_bitwise_equal_p (other, expr1, valueize)) > return true; > } > > diff --git a/gcc/match.pd b/gcc/match.pd > index 5cfe81e80b3..3204cf41538 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -200,6 +200,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (match (maybe_bit_not @0) > (bit_xor_cst@0 @1 @2)) > > +#if GIMPLE > +(match (maybe_truncate @0) > + (convert @0) > + (if (INTEGRAL_TYPE_P (type) > + && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0))))) > +#endif > + > /* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x> > ABSU_EXPR returns unsigned absolute value of the operand and the operand > of the ABSU_EXPR will have the corresponding signed type. */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c > b/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c > new file mode 100644 > index 00000000000..000c5aef237 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c > @@ -0,0 +1,34 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-optimized-raw" } */ > +/* PR tree-optimization/115449 */ > + > +void setBit_un(unsigned char *a, int b) { > + unsigned char c = 0x1UL << b; > + *a &= ~c; > + *a |= c; > +} > + > +void setBit_sign(signed char *a, int b) { > + signed char c = 0x1UL << b; > + *a &= ~c; > + *a |= c; > +} > + > +void setBit(char *a, int b) { > + char c = 0x1UL << b; > + *a &= ~c; > + *a |= c; > +} > +/* > + All three should produce: > + _1 = 1 << b_4(D); > + c_5 = (cast) _1; > + _2 = *a_7(D); > + _3 = _2 | c_5; > + *a_7(D) = _3; > + Removing the `&~c` as we are matching `(~x & y) | x` -> `x | y` > + match pattern even with extra casts are being involved. */ > + > +/* { dg-final { scan-tree-dump-not "bit_not_expr, " "optimized" } } */ > +/* { dg-final { scan-tree-dump-not "bit_and_expr, " "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "bit_ior_expr, " 3 "optimized" } } */ > -- > 2.43.0 >