>From 045a3b18715f06398c4ad7bdc2264c7ea231d579 Mon Sep 17 00:00:00 2001
From: Kael Andrew Alonzo Franco <[email protected]>
Date: Mon, 15 Jun 2026 14:54:28 -0400
Subject: [PATCH] match: Optimize bit_ior/bit_and {bit_not} rshift to
min/max [PR125641]
Fold x | (x >> (TYPE_PRECISION (type) - 1)) to max (x, -1)
Fold x | (~ (x >> (TYPE_PRECISION (type) - 1))) to min (x, -1)
Fold x & (x >> (TYPE_PRECISION (type) - 1)) to min (x, 0)
Fold x & (~ (x >> (TYPE_PRECISION (type) - 1))) to max (x, 0)
Bootstrapped and tested on x86_64-pc-linux-gnu
PR tree-optimization/125641
gcc/ChangeLog:
PR tree-optimization/125641
* match.pd: Add bit_ior/bit_and {bit_not} rshift to min/max.
gcc/testsuite/ChangeLog:
PR tree-optimization/125641
* gcc.dg/pr125641.c: New test.
Signed-off-by: Kael Franco <[email protected]>
---
gcc/match.pd | 23 ++++++++++++++++++
gcc/testsuite/gcc.dg/pr125641.c | 42 +++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr125641.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 21b0945943b..e57f1ea8622 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -5056,6 +5056,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op @0 { build_int_cst (TREE_TYPE (@1), prec - 1); })))
(op @0 { build_int_cst (TREE_TYPE (@1), low); })))))))
+/* Fold x | (x >> (TYPE_PRECISION (type) - 1)) to max (x, -1)
+ Fold x | (~ (x >> (TYPE_PRECISION (type) - 1))) to min (x, -1)
+ Fold x & (x >> (TYPE_PRECISION (type) - 1)) to min (x, 0)
+ Fold x & (~ (x >> (TYPE_PRECISION (type) - 1))) to max (x, 0)
+*/
+#ifdef GIMPLE
+(for bitop (bit_ior bit_and)
+ result (max min)
+ rresult (min max)
+ (simplify
+ (bitop:c @0 (rshift @0 INTEGER_CST@1))
+ (if (INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && wi::eq_p (wi::to_wide (@1), TYPE_PRECISION (type) - 1))
+ (result @0 { build_int_cst (type, bitop == BIT_IOR_EXPR ? -1 : 0); })))
+ (simplify
+ (bitop:c @0 (bit_not (rshift @0 INTEGER_CST@1)))
+ (if (INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && wi::eq_p (wi::to_wide (@1), TYPE_PRECISION (type) - 1))
+ (rresult @0 { build_int_cst (type, bitop == BIT_IOR_EXPR ? -1 : 0); }))))
+#endif
+
/* Fold `1 >> a` into `a == 0` for scalar integral types. */
(simplify
(rshift integer_onep @2)
diff --git a/gcc/testsuite/gcc.dg/pr125641.c b/gcc/testsuite/gcc.dg/pr125641.c
new file mode 100644
index 00000000000..4a1e240e8e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr125641.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+static int int_prec = sizeof (int) * __CHAR_BIT__ - 1;
+
+int
+max_i32 (int x, int k)
+{
+ return x < k ? k : x;
+}
+
+int
+min_i32 (int x, int k)
+{
+ return x > k ? k : x;
+}
+
+_Bool
+x_bit_ior_rshift_x (int x)
+{
+ return (x | (x >> int_prec)) == max_i32 (x, -1);
+}
+
+_Bool
+x_bit_ior_bit_not_rshift_x (int x)
+{
+ return (x | ~(x >> int_prec)) == min_i32 (x, -1);
+}
+
+_Bool
+x_bit_and_rshift_x (int x)
+{
+ return (x & (x >> int_prec)) == min_i32 (x, 0);
+}
+
+_Bool
+x_bit_and_bit_not_rshift_x (int x)
+{
+ return (x & ~(x >> int_prec)) == max_i32 (x, 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1;" 4 "optimized" } } */
--
2.54.0
On Tue, Jun 9, 2026 at 1:08 PM Kael Andrew Franco <[email protected]>
wrote:
> From 712dd974acd5a972d74e62e8eec902de9c557a26 Mon Sep 17 00:00:00 2001
> From: Kael Andrew Alonzo Franco <[email protected]>
> Date: Tue, 9 Jun 2026 05:59:57 -0400
> Subject: [PATCH] match: Optimize bit_ior/bit_and {bit_not} rshift to min/max
> [PR125641]
>
> Fold x | (x >> (TYPE_PRECISION (type) - 1)) to max (x, -1)
> Fold x | (~ (x >> (TYPE_PRECISION (type) - 1))) to min (x, -1)
> Fold x & (x >> (TYPE_PRECISION (type) - 1)) to min (x, 0)
> Fold x & (~ (x >> (TYPE_PRECISION (type) - 1))) to max (x, 0)
>
> Bootstrapped and tested on x86_64-pc-linux-gnu
>
> PR tree-optimization/125641
>
> gcc/ChangeLog:
>
> PR tree-optimization/125641
> * match.pd: Add bit_ior/bit_and {bit_not} rshift to min/max.
>
> gcc/testsuite/ChangeLog:
>
> PR tree-optimization/125641
> * gcc.dg/pr125641.c: New test.
>
> Signed-off-by: Kael Franco <[email protected]>
> ---
> gcc/match.pd | 23 +++++++++++++++++++
> gcc/testsuite/gcc.dg/pr125641.c | 40 +++++++++++++++++++++++++++++++++
> 2 files changed, 63 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/pr125641.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index e0d7ef80e14..015a12c6055 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -5043,6 +5043,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> (op @0 { build_int_cst (TREE_TYPE (@1), prec - 1); })))
> (op @0 { build_int_cst (TREE_TYPE (@1), low); })))))))
>
> +/* Fold x | (x >> (TYPE_PRECISION (type) - 1)) to max (x, -1)
> + Fold x | (~ (x >> (TYPE_PRECISION (type) - 1))) to min (x, -1)
> + Fold x & (x >> (TYPE_PRECISION (type) - 1)) to min (x, 0)
> + Fold x & (~ (x >> (TYPE_PRECISION (type) - 1))) to max (x, 0)
> +*/
> +#ifdef GIMPLE
> +(for bitop (bit_ior bit_and)
> + result (max min)
> + rresult (min max)
> + (simplify
> + (bitop:c @0 (rshift @0 INTEGER_CST@1))
> + (if (INTEGRAL_TYPE_P (type)
> + && !TYPE_UNSIGNED (type)
> + && wi::eq_p (wi::to_wide (@1), TYPE_PRECISION (type) - 1))
> + (result @0 { build_int_cst (type, bitop == BIT_IOR_EXPR ? -1 : 0); })))
> + (simplify
> + (bitop:c @0 (bit_not (rshift @0 INTEGER_CST@1)))
> + (if (INTEGRAL_TYPE_P (type)
> + && !TYPE_UNSIGNED (type)
> + && wi::eq_p (wi::to_wide (@1), TYPE_PRECISION (type) - 1))
> + (rresult @0 { build_int_cst (type, bitop == BIT_IOR_EXPR ? -1 : 0); }))))
> +#endif
> +
> /* Fold `1 >> a` into `a == 0` for scalar integral types. */
> (simplify
> (rshift integer_onep @2)
> diff --git a/gcc/testsuite/gcc.dg/pr125641.c b/gcc/testsuite/gcc.dg/pr125641.c
> new file mode 100644
> index 00000000000..690d1c70d1f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr125641.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +int
> +max_i32 (int x, int k)
> +{
> + return x < k ? k : x;
> +}
> +
> +int
> +min_i32 (int x, int k)
> +{
> + return x > k ? k : x;
> +}
> +
> +_Bool
> +x_bit_ior_rshift_x (int x)
> +{
> + return (x | (x >> 31)) == max_i32 (x, -1);
> +}
> +
> +_Bool
> +x_bit_ior_bit_not_rshift_x (int x)
> +{
> + return (x | ~(x >> 31)) == min_i32 (x, -1);
> +}
> +
> +_Bool
> +x_bit_and_rshift_x (int x)
> +{
> + return (x & (x >> 31)) == min_i32 (x, 0);
> +}
> +
> +_Bool
> +x_bit_and_bit_not_rshift_x (int x)
> +{
> + return (x & ~(x >> 31)) == max_i32 (x, 0);
> +}
> +
> +/* { dg-final { scan-tree-dump-times "return 1;" 4 "optimized" } } */
> --
> 2.54.0
>
>
>
>