On 8/31/26 2:56 AM, Avinal Kumar wrote:
The pattern that folds (X >> C1) & C2 and (X << C1) & C2 was limited
to types with precision <= HOST_BITS_PER_WIDE_INT because it used
unsigned HOST_WIDE_INT for mask and zerobits arithmetic.  This prevents
the optimization from firing on __int128 and wider types at the GIMPLE
level.

Convert the pattern to use wide_int and remove the TYPE_PRECISION guard.
Replace the mode-mask loop with wi::exact_log2 (newmask + 1) to check
whether newmask is (2^n - 1) for a power-of-two n >= BITS_PER_UNIT.
Handle the case where newmask is all-ones at full type precision
separately, since newmask + 1 overflows to zero in that case.

         PR120524
         PR tree-optimization/120524

gcc/ChangeLog:

         * match.pd: Use wide_int for shift-and-mask folding [PR120524]

gcc/testsuite/ChangeLog:

         * gcc.dg/tree-ssa/pr120524.c: New test.

Signed-off-by: Avinal Kumar <[email protected]>
No concerns with the match.pd change.  It looks like a straightforward conversion to wi::  While there are things that could perhaps be considered "better" by using the operators provided by wi:: rather than explicit method calls, those are purely style preferences.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr120524.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr120524.c
new file mode 100644
index 00000000000..b9d9bae74ff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr120524.c
@@ -0,0 +1,28 @@
+/* PR tree-optimization/120524 */
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Verify (a >> 127) & 1 is optimized to (unsigned __int128)a >> 127.
+   The mask 1 covers all sign-extended bits, so the arithmetic right shift
+   can be converted to a logical right shift.  */
+__int128 f1(__int128 a) { return (a >> 127) & 1; }
+
+/* Verify (a >> 120) & 0xff is similarly optimized.  */
+__int128 f2(__int128 a) { return (a >> 120) & 0xff; }
+
+/* Verify the left shift path of the same pattern also works for 128-bit
+   types.  The mask isolates only the shifted bits, so the redundant lower
+   bits can be folded into the mask.  */
+__int128 f3(__int128 a) { return (a << 120) & ((__int128)0xff << 120); }
+
+/* f1, f2: arithmetic right shifts should be converted to logical shifts.  */
+/* { dg-final { scan-tree-dump "uint128_t" "optimized" } } */
+
+/* Verify 64-bit case also works, this is folded by C frontend putting it
+   here as regression guard.  */
+long long f4(long long a) { return (a >> 63) & 1; }
+
+/* All BIT_AND masks should be folded away.  */
+/* { dg-final { scan-tree-dump-not "& 1" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "& 255" "optimized" } } */
The test seems a bit weak.  f1 and f2 both generate a AND expression in the .optimized dump without your patch.  So you can correctly infer your optimization fired for those.  However f3/f4 do not seem to be covered as I don't see any AND expressions in their .optimized dump without your patch.  Finding a way to verify the f3/f4 cases seems like the only blocking issue.


Jeff

Reply via email to