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