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