On Thu, 30 Jul 2026, Jakub Jelinek wrote:

> On Wed, Jul 29, 2026 at 05:09:43PM -0700, Andrea Pinski wrote:
> > > --- gcc/match.pd.jj     2026-07-29 17:21:33.893285488 +0200
> > > +++ gcc/match.pd        2026-07-29 17:17:59.855012063 +0200
> > > @@ -5293,7 +5293,11 @@ (define_operator_list SYNC_FETCH_AND_AND
> > >    (cmp (bit_and (lshift integer_pow2p@1 @0) integer_pow2p@2) 
> > > integer_zerop)
> > >     (with { int c1 = wi::clz (wi::to_wide (@1));
> > >            int c2 = wi::clz (wi::to_wide (@2)); }
> > > -    (if (c1 < c2)
> > > +    (if (c1 < c2
> > > +        /* If c1 - c2 isn't representable in TREE_TYPE (@0), it is also
> > > +           never true, because for any valid x C << x will be smaller
> > > +           than D.  See PR126476.  */
> > > +        || c1 - c2 > wi::to_widest (TYPE_MAX_VALUE (TREE_TYPE (@0))))
> > 
> > I was worried that TYPE_MAX_VALUE might not be constant but we depend
> > on it being constant in other places.
> 
> On a second thought, I think comparison with TYPE_MAX_VALUE is not what
> we want, even for limited range type build_int_cst will happily create
> larger constants.
> 
> So, I think we should go with the following instead.
> wi::shwi (c1 - c2, HOST_BITS_PER_INT) will always fit and fits_to_tree_p
> will then check if build_int_cst will work or not.

LGTM.

> 2026-07-30  Jakub Jelinek  <[email protected]>
> 
>       PR tree-optimization/126476
>       * match.pd (((C << A) & D) != 0 -> A == 0,
>       ((C << A) & D) == 0 -> A != 0): Fold to false/true if
>       c1 - c2 resp. c2 - c1 doesn't fit into TREE_TYPE (@0).
> 
>       * gcc.dg/torture/bitint-103.c: New test.
> 
> --- gcc/match.pd.jj   2026-07-30 09:55:49.767353123 +0200
> +++ gcc/match.pd      2026-07-30 10:30:26.284706405 +0200
> @@ -5265,7 +5265,12 @@ (define_operator_list SYNC_FETCH_AND_AND
>    (cmp (bit_and (lshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop)
>     (with { int c1 = wi::clz (wi::to_wide (@1));
>          int c2 = wi::clz (wi::to_wide (@2)); }
> -    (if (c1 < c2)
> +    (if (c1 < c2
> +      /* If c1 - c2 isn't representable in TREE_TYPE (@0), it is also
> +         never true, because for any valid x C << x will be smaller
> +         than D.  See PR126476.  */
> +      || !wi::fits_to_tree_p (wi::shwi (c1 - c2, HOST_BITS_PER_INT),
> +                              TREE_TYPE (@0)))
>       { constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
>       (icmp @0 { build_int_cst (TREE_TYPE (@0), c1 - c2); }))))
>   (simplify
> @@ -5273,7 +5278,9 @@ (define_operator_list SYNC_FETCH_AND_AND
>     (if (tree_int_cst_sgn (@1) > 0)
>      (with { int c1 = wi::clz (wi::to_wide (@1));
>           int c2 = wi::clz (wi::to_wide (@2)); }
> -     (if (c1 > c2)
> +     (if (c1 > c2
> +       || !wi::fits_to_tree_p (wi::shwi (c2 - c1, HOST_BITS_PER_INT),
> +                               TREE_TYPE (@0)))
>        { constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
>        (icmp @0 { build_int_cst (TREE_TYPE (@0), c2 - c1); }))))))
>  
> --- gcc/testsuite/gcc.dg/torture/bitint-103.c.jj      2026-07-30 
> 10:28:31.349777715 +0200
> +++ gcc/testsuite/gcc.dg/torture/bitint-103.c 2026-07-30 10:28:31.349777715 
> +0200
> @@ -0,0 +1,22 @@
> +/* PR tree-optimization/126476 */
> +/* { dg-do run { target bitint } } */
> +
> +[[gnu::noipa]] int
> +foo (unsigned _BitInt(4) n)
> +{
> +  return ((1ULL << n) & (1ULL << 20)) != 0;
> +}
> +
> +[[gnu::noipa]] int
> +bar (unsigned _BitInt(4) n)
> +{
> +  return (((1ULL << 40) >> n) & (1ULL << 20)) != 0;
> +}
> +
> +int
> +main ()
> +{
> +  for (unsigned i = 0; i < 16; i++)
> +    if (foo (i) != 0 || bar (i) != 0)
> +        __builtin_abort ();
> +}
> 
> 
>       Jakub
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to