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)