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.

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

Reply via email to