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. 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