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)

Reply via email to