On Sun, Jan 11, 2026 at 10:05 PM Andrew Pinski
<[email protected]> wrote:
>
> This adds the simpliciation of:
> ```
> <unnamed-signed:3> _1;
>
> _2 = (signed char) _1;
> _3 = _2 ^ -47;
> _4 = (<unnamed-signed:3>) _3;
> ```
>
> to:
> ```
> <unnamed-signed:3> _n;
> _4 = _1 ^ -47;
> ```
>
> This also fixes PR 122843 by optimizing out the xor such that we get:
> ```
> _1 = b.a;
> _21 = (<unnamed-signed:3>) t_23(D);
> // t_23 in the original testcase was 200 so this is reduced to 0
> _5 = _1 ^ _21;
> # .MEM_24 = VDEF <.MEM_13>
> b.a = _5;
> ```
> And then there is no cast catch this pattern:
> `(bit_xor (convert1? (bit_xor:c @0 @1)) (convert2? (bit_xor:c @0 @2)))`
> As we get:
> ```
> _21 = (<unnamed-signed:3>) t_23(D);
> _5 = _1 ^ _21;
> _22 = (<unnamed-signed:3>) t_23(D);
> _7 = _5 ^ _22;
> _25 = (<unnamed-signed:3>) t_23(D);
> _8 = _7 ^ _25;
> _26 = (<unnamed-signed:3>) t_23(D);
> _9 = _7 ^ _26;
> ```
> After unrolling and then fre will optimize away all of those xor.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> PR tree-optimization/122845
> PR tree-optimization/122843
> gcc/ChangeLog:
>
> * match.pd (`(T1)(a bit_op (T2)b)`): Also
> simplify if T1 is the same type as b and T2 is wider
> type than T1.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/bitops-12.c: New test.
> * gcc.dg/tree-ssa/bitops-13.c: New test.
> * gcc.dg/store_merging_18.c: xfail store merging.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/match.pd | 10 +++++++++-
> gcc/testsuite/gcc.dg/store_merging_18.c | 3 ++-
> gcc/testsuite/gcc.dg/tree-ssa/bitops-12.c | 18 ++++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/bitops-13.c | 18 ++++++++++++++++++
> 4 files changed, 47 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bitops-12.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bitops-13.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 492d88514fc..16ce2d1edd2 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2323,7 +2323,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> && !POINTER_TYPE_P (TREE_TYPE (@0))
> && TREE_CODE (TREE_TYPE (@0)) != OFFSET_TYPE
> && TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (type))
> - (bitop:type (convert @0) (convert @1)))))
> + (bitop:type (convert @0) (convert @1))
> + /* Similar as above, but the outer and inner most types match
> + and it was widening cast; replacing 2 casts with only one. */
> + (if (GIMPLE
> + && INTEGRAL_TYPE_P (type)
> + && INTEGRAL_TYPE_P (TREE_TYPE (@0))
> + && types_match (type, TREE_TYPE (@0))
> + && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (type))
I think you need the pointer and offset type checks here as well given
bitops are not valid on those in general.
OK with adding those.
Richard.
> + (bitop:type @0 (convert @1))))))
>
> (for bitop (bit_and bit_ior)
> rbitop (bit_ior bit_and)
> diff --git a/gcc/testsuite/gcc.dg/store_merging_18.c
> b/gcc/testsuite/gcc.dg/store_merging_18.c
> index fdff6b4d812..546c17dc7c4 100644
> --- a/gcc/testsuite/gcc.dg/store_merging_18.c
> +++ b/gcc/testsuite/gcc.dg/store_merging_18.c
> @@ -1,7 +1,8 @@
> /* PR tree-optimization/83843 */
> /* { dg-do run } */
> /* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-store-merging" } */
> -/* { dg-final { scan-tree-dump-times "Merging successful" 3 "store-merging"
> { target { store_merge && { ! arm*-*-* } } } } } */
> +/* xfailed after PR 122845, see PR 123541 ( */
> +/* { dg-final { scan-tree-dump-times "Merging successful" 3 "store-merging"
> { target { store_merge && { ! arm*-*-* } } xfail *-*-* } } } */
>
> __attribute__((noipa)) void
> foo (unsigned char *buf, unsigned char *tab)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitops-12.c
> b/gcc/testsuite/gcc.dg/tree-ssa/bitops-12.c
> new file mode 100644
> index 00000000000..50d8dc2180f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/bitops-12.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -fdump-tree-optimized-raw" } */
> +/* PR tree-optimization/122845 */
> +
> +struct s1
> +{
> + signed f1:3;
> +};
> +struct s1 p;
> +void f(void)
> +{
> + p.f1 ^= -47;
> + p.f1 ^= -47;
> +}
> +
> +/* There should be no gimple stmts left except for return.
> + That is the ^ has been optimized away. */
> +/* { dg-final { scan-tree-dump-not "gimple_assign <" "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitops-13.c
> b/gcc/testsuite/gcc.dg/tree-ssa/bitops-13.c
> new file mode 100644
> index 00000000000..ecf69738267
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/bitops-13.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -fdump-tree-optimized-raw" } */
> +/* PR tree-optimization/122845 */
> +
> +int f(signed char a, int b)
> +{
> + int aa = a;
> + int bb = b;
> + aa &= bb;
> + signed char t = aa;
> + aa = t;
> + aa &= bb;
> + t = aa;
> + return t;
> +}
> +
> +/* There should be only 1 bit_and_expr left as both ands are the same. */
> +/* { dg-final { scan-tree-dump-times "bit_and_expr, " 1 "optimized" } } */
> --
> 2.43.0
>