Re: [PATCH] match.pd: build signed low-bit masks in an unsigned type

Kyrylo Tkachov <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>

> 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 (application/octet-stream, 11.2 KB)
From b9104974eadf573757d290d942bd4887d667202a Mon Sep 17 00:00:00 2001
From: Kyrylo Tkachov <[email protected]>
Date: Sat, 15 Aug 2026 12:06:01 +0200
Subject: [PATCH] match.pd: build signed low-bit masks in an unsigned type

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.

Canonicalize subtraction of an integral vector constant into addition of its
negation when all encoded elements can be negated without overflow.  This
lets the low-bit-mask rule use only the canonical addition of minus one.

The signed mask 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.  Also keep
a vector subtraction when a constant element is the signed minimum or the
operation is instrumented for overflow.

The canonicalized producer remains visible before dead-code elimination in
one existing forwprop dump.  Adjust its addition count.

Bootstrapped and tested on aarch64-none-linux-gnu.
Tested on x86_64-pc-linux-gnu.

gcc/ChangeLog:

	* match.pd (x & ((1 << b) - 1)): Handle signed scalar and vector
	types.
	(negate_expr_p): Handle non-wrapping integral vector constants.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/forwprop-27.c: Adjust the expected addition count.
	* 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.
	* gcc.dg/tree-ssa/vector-sub-const-1.c: Likewise.
	* gcc.dg/tree-ssa/vector-sub-const-2.c: Likewise.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/match.pd                                  | 45 +++++++++++++++----
 gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c   |  2 +-
 .../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 ++++++++++
 .../gcc.dg/tree-ssa/vector-sub-const-1.c      | 26 +++++++++++
 .../gcc.dg/tree-ssa/vector-sub-const-2.c      | 12 +++++
 9 files changed, 155 insertions(+), 9 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/vector-sub-const-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c

diff --git a/gcc/match.pd b/gcc/match.pd
index eae8717bcfe..dc51f79c58c 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1577,11 +1577,20 @@ 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.  */
+(simplify
+ (bit_and:c @0
+  (plus:s (lshift:s integer_onep @1) integer_minus_onep))
+ (with { tree etype = VECTOR_TYPE_P (type) ? TREE_TYPE (type) : type; }
+  (if (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))))))))
 
 /* PR112533: Canonicalize boolean comparisons of masked pow2 bits into
    xor-mask tests.
@@ -2428,11 +2437,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (match negate_expr_p
  REAL_CST
  (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)))))
-/* VECTOR_CST handling of non-wrapping types would recurse in unsupported
-   ways.  */
+/* A non-wrapping integral vector constant can be negated when none of its
+   encoded elements is the minimum value.  */
 (match negate_expr_p
  VECTOR_CST
- (if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type))))
+ (with
+  {
+    tree etype = TREE_TYPE (type);
+    bool negatable = (FLOAT_TYPE_P (etype) || TYPE_OVERFLOW_WRAPS (type));
+    if (!negatable
+	&& INTEGRAL_TYPE_P (etype)
+	&& !TYPE_OVERFLOW_SANITIZED (etype))
+      {
+	negatable = true;
+	if (!TYPE_UNSIGNED (etype))
+	  for (unsigned int i = 0; i < vector_cst_encoded_nelts (t); ++i)
+	    if (TREE_CODE (VECTOR_CST_ENCODED_ELT (t, i)) != INTEGER_CST
+		|| !may_negate_without_overflow_p
+		     (VECTOR_CST_ENCODED_ELT (t, i)))
+	      {
+		negatable = false;
+		break;
+	      }
+      }
+  }
+  (if (negatable))))
 (match negate_expr_p
  (minus @0 @1)
  (if ((ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
index 6c71a4fc81c..29d39c67c79 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
@@ -33,7 +33,7 @@ void i (V *v1, V *v2){
   *v2 = (c1-*v2)+c2;
 }
 
-/* { dg-final { scan-tree-dump-times "\\\+" 1 "forwprop1"} } */
+/* { dg-final { scan-tree-dump-times "\\\+" 2 "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 0, 4 }" "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 37, -5 }" "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 27, 23 }" "forwprop1"} } */
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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c
new file mode 100644
index 00000000000..229ca60dde4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1" } */
+
+typedef __INT32_TYPE__ v4si __attribute__ ((vector_size (16)));
+
+v4si
+sub_splat (v4si x)
+{
+  return x - (v4si) { 1, 1, 1, 1 };
+}
+
+v4si
+sub_mixed (v4si x)
+{
+  return x - (v4si) { 1, -2, 3, -4 };
+}
+
+v4si
+keep_min (v4si x)
+{
+  return x - (v4si) { -__INT32_MAX__ - 1, 1, 1, 1 };
+}
+
+/* { dg-final { scan-tree-dump-times " \\+ \\{ -1, -1, -1, -1 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " \\+ \\{ -1, 2, -3, 4 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " - \\{ -2147483648, 1, 1, 1 \\}" 1 "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c
new file mode 100644
index 00000000000..27de9e77be2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-psabi -fsanitize=signed-integer-overflow -fdump-tree-forwprop1" } */
+
+typedef __INT32_TYPE__ v4si __attribute__ ((vector_size (16)));
+
+v4si
+f (v4si x)
+{
+  return x - (v4si) { 1, 1, 1, 1 };
+}
+
+/* { dg-final { scan-tree-dump-times "\\.UBSAN_CHECK_SUB" 1 "forwprop1" } } */
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.