On Thu, 21 Aug 2025, dhr...@nvidia.com wrote: > From: Dhruv Chawla <dhr...@nvidia.com> > > Bootstrapped and regtested on aarch64-linux-gnu. > > Signed-off-by: Dhruv Chawla <dhr...@nvidia.com> > > gcc/ChangeLog: > > * match.pd: New pattern. > > gcc/testsuite/ChangeLog: > > * gcc.dg/match-constant-shift-1.c: New test. > * gcc.dg/match-constant-shift-1.c: Likewise. > --- > gcc/match.pd | 7 +++++ > gcc/testsuite/gcc.dg/match-constant-shift-1.c | 17 ++++++++++++ > gcc/testsuite/gcc.dg/match-constant-shift-2.c | 27 +++++++++++++++++++ > 3 files changed, 51 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/match-constant-shift-1.c > create mode 100644 gcc/testsuite/gcc.dg/match-constant-shift-2.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 66e8a787449..3d462659d03 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -1316,6 +1316,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (if (INTEGRAL_TYPE_P (type)) > (rshift (op @0 @2) @1)))) > > +/* (C << x) == x -> 0 when C != 0. */ > +(simplify > + (eq:c (nop_convert? (lshift INTEGER_CST@0 @1)) @1)
The pattern misses the corresponding handling for (C << x) {!=,<,>,<=,>=} x You can generalize this to non-constant @0 by checking for tree_expr_nonzero_p (@0). > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1)) > + && !integer_zerop (@0)) > + { build_zero_cst (type); })) > + > /* Fold (1 << (C - x)) where C = precision(type) - 1 > into ((1 << C) >> x). */ > (simplify > diff --git a/gcc/testsuite/gcc.dg/match-constant-shift-1.c > b/gcc/testsuite/gcc.dg/match-constant-shift-1.c > new file mode 100644 > index 00000000000..7d4afad5a49 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/match-constant-shift-1.c > @@ -0,0 +1,17 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-gimple" } */ > + > +#define TEST(type, cst) > \ > + type lshift_##type (type x) { return (type) ((cst << x) == x); } > + > +typedef enum > +{ > + ZERO > +} test_enum; > + > +TEST (unsigned, 1) > +TEST (int, -1) > +TEST (bool, -5) > +TEST (test_enum, -6) > + > +/* { dg-final { scan-tree-dump-not "<<" gimple } } */ > diff --git a/gcc/testsuite/gcc.dg/match-constant-shift-2.c > b/gcc/testsuite/gcc.dg/match-constant-shift-2.c > new file mode 100644 > index 00000000000..62b39e3e790 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/match-constant-shift-2.c > @@ -0,0 +1,27 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-gimple" } */ > + > +/* The fold (C << x) == x -> 0 shouldn't trigger when C is 0. It ends up > + getting folded to x == 0 in that case. */ > + > +#define TEST(type, cst) > \ > + type lshift_##type (type x) { return (type) ((cst << x) == x); } > + > +typedef unsigned _BitInt (6) bit_int; > + > +typedef enum > +{ > + ZERO > +} test_enum; > + > +TEST (unsigned, 0) > +TEST (int, 0) > +TEST (bool, 0) > +/* Bitints are not supported by the fold. */ > +TEST (bit_int, 0) > +TEST (test_enum, 0) > + > +/* This ends up getting folded by another pattern. */ > +/* { dg-final { scan-tree-dump-times "x == 0" 4 gimple } } */ > +/* bool gets optimized differently. */ > +/* { dg-final { scan-tree-dump-times "~x" 1 gimple } } */ > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)