> On 19 Aug 2026, at 07:54, Andrea Pinski <[email protected]> > wrote: > > On Mon, Aug 17, 2026 at 5:59 AM <[email protected]> wrote: >> >> From: Kyrylo Tkachov <[email protected]> >> >> The PR71636 fold turns >> >> x & ((1U << b) - 1) >> >> into >> >> x & ~(~0U << b) >> >> but only when the mask type is unsigned. Signed source and vector forms keep >> the longer expression. >> >> int f (int x, int b) >> { >> return x & ((1 << b) - 1); >> } >> >> aarch64 -O2 before: >> >> f: >> mov w2, 1 >> lsl w2, w2, w1 >> sub w2, w2, #1 >> and w0, w2, w0 >> ret >> >> aarch64 -O2 after: >> >> f: >> mov w2, -1 >> lsl w2, w2, w1 >> bic w0, w0, w2 >> ret >> >> Build a signed mask in the corresponding unsigned type and convert it back. >> This makes the all-ones shift defined and exposes the shorter form. Accept >> both the canonical addition of minus one and a direct subtraction so the rule >> also handles vector expressions. >> >> The signed form is not valid when the source subtraction can trap or is >> instrumented for overflow. It can also remove the signed shift-base check >> for >> the top-bit count. Keep these cases. After GIMPLE lowering, an explicit >> shift sanitizer check remains visible, so the fold is safe again. >> >> Bootstrapped and tested on aarch64-none-linux-gnu. >> Ok for trunk? >> Thanks, >> Kyrill >> >> gcc/ChangeLog: >> >> * match.pd (x & ((1 << b) - 1)): Handle signed scalar and vector >> types. >> >> gcc/testsuite/ChangeLog: >> >> * gcc.dg/tree-ssa/pr71636-signed-1.c: New test. >> * gcc.dg/tree-ssa/pr71636-signed-vector-1.c: Likewise. >> * gcc.dg/tree-ssa/pr71636-signed-trap-1.c: Likewise. >> * gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c: Likewise. >> * gcc.dg/tree-ssa/pr71636-signed-shift-ubsan-1.c: Likewise. >> >> Signed-off-by: Kyrylo Tkachov <[email protected]> >> --- >> gcc/match.pd | 23 ++++++++++++++---- >> .../gcc.dg/tree-ssa/pr71636-signed-1.c | 24 +++++++++++++++++++ >> .../tree-ssa/pr71636-signed-shift-ubsan-1.c | 11 +++++++++ >> .../gcc.dg/tree-ssa/pr71636-signed-trap-1.c | 10 ++++++++ >> .../gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c | 10 ++++++++ >> .../gcc.dg/tree-ssa/pr71636-signed-vector-1.c | 24 +++++++++++++++++++ >> 6 files changed, 97 insertions(+), 5 deletions(-) >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-1.c >> create mode 100644 >> gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-shift-ubsan-1.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-trap-1.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-1.c >> >> diff --git a/gcc/match.pd b/gcc/match.pd >> index 02684d8a302..4ead7bc316c 100644 >> --- a/gcc/match.pd >> +++ b/gcc/match.pd >> @@ -1558,11 +1558,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >> (convert @0) >> (convert @1))))) >> >> -/* PR71636: Transform x & ((1U << b) - 1) -> x & ~(~0U << b); */ >> -(simplify >> - (bit_and:c @0 (plus:s (lshift:s integer_onep @1) integer_minus_onep)) >> - (if (TYPE_UNSIGNED (type)) >> - (bit_and @0 (bit_not (lshift { build_all_ones_cst (type); } @1))))) >> +/* PR71636: Transform x & ((1U << b) - 1) -> x & ~(~0U << b). For signed >> + types, build the mask in the corresponding unsigned type, where shifting >> + all ones left is defined. Preserve signed overflow and shift checks. */ >> +(for sub (plus minus) >> + (simplify >> + (bit_and:c @0 >> + (sub:s (lshift:s integer_onep @1) uniform_integer_cst_p@2)) >> + (with { tree cst = uniform_integer_cst_p (@2); >> + tree etype = VECTOR_TYPE_P (type) ? TREE_TYPE (type) : type; } >> + (if ((sub == PLUS_EXPR ? integer_minus_onep (cst) : integer_onep (cst)) >> + && INTEGRAL_TYPE_P (etype) >> + && (TYPE_UNSIGNED (etype) >> + || (!TYPE_OVERFLOW_TRAPS (etype) >> + && !TYPE_OVERFLOW_SANITIZED (etype) >> + && (GIMPLE || !sanitize_flags_p (SANITIZE_SHIFT_BASE))))) >> + (with { tree utype = unsigned_type_for (type); } >> + (bit_and @0 (convert >> + (bit_not (lshift { build_all_ones_cst (utype); } >> @1))))))))) > > > It seems like we should canonicalize `a - {1,1,1,1}` into `a + > {-1,-1,-1,-1}` and not need the above mess of checking for `a + -1`/`a > - 1`. > Can you add that? That is `a - VECTOR_CST` transform into `a + > (-VECTOR_CST)`. Test on both x86_64 and aarch64 to see if there any > fall out as there might be.
Something like the attached? It passes clean on aarch64 and x86_64.
Thanks,
Kyrill
>
>>
>> (for bitop (bit_and bit_ior)
>> cmp (eq ne)
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-1.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-1.c
>> new file mode 100644
>> index 00000000000..9db533fdf64
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-1.c
>> @@ -0,0 +1,24 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fdump-tree-optimized" } */
>> +
>> +int
>> +f_signed (int x, int b)
>> +{
>> + return x & ((1 << b) - 1);
>> +}
>> +
>> +unsigned int
>> +f_unsigned (unsigned int x, int b)
>> +{
>> + return x & ((1U << b) - 1U);
>> +}
>> +
>> +long
>> +f_long (long x, int b)
>> +{
>> + return x & ((1L << b) - 1L);
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-not "1 <<" "optimized" } } */
>> +/* { dg-final { scan-tree-dump-not " \\+ -1;" "optimized" } } */
>> +/* { dg-final { scan-tree-dump-times "= ~" 3 "optimized" } } */
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-shift-ubsan-1.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-shift-ubsan-1.c
>> new file mode 100644
>> index 00000000000..3abee74264c
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-shift-ubsan-1.c
>> @@ -0,0 +1,11 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fsanitize=shift-base -fdump-tree-optimized" } */
>> +
>> +int
>> +f (int x, int b)
>> +{
>> + return x & ((1 << b) - 1);
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-times
>> "__builtin___ubsan_handle_shift_out_of_bounds" 1 "optimized" } } */
>> +/* { dg-final { scan-tree-dump-times "= ~" 1 "optimized" } } */
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-trap-1.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-trap-1.c
>> new file mode 100644
>> index 00000000000..13a1a5b4cf2
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-trap-1.c
>> @@ -0,0 +1,10 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -ftrapv -fdump-tree-optimized" } */
>> +
>> +int
>> +f (int x, int b)
>> +{
>> + return x & ((1 << b) - 1);
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-times " \\+ -1;" 1 "optimized" } } */
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c
>> new file mode 100644
>> index 00000000000..68c1b92f18b
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-ubsan-1.c
>> @@ -0,0 +1,10 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fsanitize=signed-integer-overflow
>> -fdump-tree-optimized" } */
>> +
>> +int
>> +f (int x, int b)
>> +{
>> + return x & ((1 << b) - 1);
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-times "\\.UBSAN_CHECK_SUB" 1 "optimized" } }
>> */
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-1.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-1.c
>> new file mode 100644
>> index 00000000000..51ba0b35334
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-1.c
>> @@ -0,0 +1,24 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fdump-tree-optimized" } */
>> +/* { dg-require-effective-target vect_int } */
>> +/* { dg-require-effective-target vect_var_shift } */
>> +
>> +typedef int v4si __attribute__ ((vector_size (16)));
>> +typedef unsigned int v4ui __attribute__ ((vector_size (16)));
>> +
>> +v4si
>> +f_signed (v4si x, v4si b)
>> +{
>> + v4si one = { 1, 1, 1, 1 };
>> + return x & ((one << b) - one);
>> +}
>> +
>> +v4ui
>> +f_unsigned (v4ui x, v4ui b)
>> +{
>> + v4ui one = { 1, 1, 1, 1 };
>> + return x & ((one << b) - one);
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-not "\\{ 1, 1, 1, 1 \\} <<" "optimized" } }
>> */
>> +/* { dg-final { scan-tree-dump-times "= ~" 2 "optimized" } } */
>> --
>> 2.50.1 (Apple Git-155)
>>
0001-match.pd-build-signed-low-bit-masks-in-an-unsigned-t.patch
Description: 0001-match.pd-build-signed-low-bit-masks-in-an-unsigned-t.patch
