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

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 subtraction of one and addition of minus one.  Signed nonwrapping vectors
can retain the subtraction form, while scalar and wrapping forms can use the
addition form.

The signed form is not valid when the source addition or 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.

Vector types carry the lane signedness used by the unsigned and trapping
checks.  The first patch makes TYPE_OVERFLOW_SANITIZED accept integral vector
types.  Query the matched type directly.  Test both vector source spellings
and keep both operations under the sanitizer.

Bootstrapped and tested on aarch64-none-linux-gnu.
Tested on x86_64-pc-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-vector-ubsan-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                                  | 22 ++++++++++---
 .../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 | 32 +++++++++++++++++++
 .../tree-ssa/pr71636-signed-vector-ubsan-1.c  | 22 +++++++++++++
 7 files changed, 126 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
 create mode 100644 
gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-ubsan-1.c

diff --git a/gcc/match.pd b/gcc/match.pd
index a969aa20417..cbdc3fcf9c3 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1575,11 +1575,23 @@ 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 op (plus minus)
+ (simplify
+  (bit_and:c @0
+   (op:s (lshift:s integer_onep @1) uniform_integer_cst_p@2))
+  (with { tree cst = uniform_integer_cst_p (@2); }
+   (if ((op == PLUS_EXPR ? integer_minus_onep (cst) : integer_onep (cst))
+       && (TYPE_UNSIGNED (type)
+           || (!TYPE_OVERFLOW_TRAPS (type)
+               && !TYPE_OVERFLOW_SANITIZED (type)
+               && (GIMPLE || !sanitize_flags_p (SANITIZE_SHIFT_BASE)))))
+    (with { tree utype = unsigned_type_for (type); }
+     (bit_and @0
+      (convert:type
+       (bit_not (lshift { build_all_ones_cst (utype); } @1)))))))))
 
 /* PR112533: Canonicalize boolean comparisons of masked pow2 bits into
    xor-mask tests.
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..27ea7b5a54b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-1.c
@@ -0,0 +1,32 @@
+/* { 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);
+}
+
+v4si
+f_signed_plus (v4si x, v4si b)
+{
+  v4si one = { 1, 1, 1, 1 };
+  v4si minus_one = { -1, -1, -1, -1 };
+  return x & ((one << b) + minus_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 "= ~" 3 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-ubsan-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-ubsan-1.c
new file mode 100644
index 00000000000..58bc022bde0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71636-signed-vector-ubsan-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-psabi -fsanitize=signed-integer-overflow 
-fno-sanitize=shift-base -fdump-tree-ubsan" } */
+
+typedef int v4si __attribute__ ((vector_size (4 * sizeof (int))));
+
+v4si
+f_add (v4si x, v4si b)
+{
+  v4si one = { 1, 1, 1, 1 };
+  v4si minus_one = { -1, -1, -1, -1 };
+  return x & ((one << b) + minus_one);
+}
+
+v4si
+f_sub (v4si x, v4si b)
+{
+  v4si one = { 1, 1, 1, 1 };
+  return x & ((one << b) - one);
+}
+
+/* { dg-final { scan-tree-dump-times "\\.UBSAN_CHECK_ADD" 1 "ubsan" } } */
+/* { dg-final { scan-tree-dump-times "\\.UBSAN_CHECK_SUB" 1 "ubsan" } } */
-- 
2.50.1 (Apple Git-155)

Reply via email to