On Fri, Aug 21, 2026 at 1:34 AM Richard Biener <[email protected]> wrote: > > On Thu, 20 Aug 2026, [email protected] wrote: > > > From: Kyrylo Tkachov <[email protected]> > > > > The A - B -> A + (-B) rule uses negate_expr_p to decide whether B can be > > negated cheaply. The predicate rejects non-wrapping integral vector > > constants, even when every encoded element can be negated without overflow. > > This leaves vector subtraction in a noncanonical form and can hide an > > encodable constant from target expansion. > > > > typedef int v4si __attribute__ ((vector_size (16))); > > > > v4si > > f (v4si x) > > { > > return x - (v4si) { -16711935, -16711935, -16711935, -16711935 }; > > } > > > > aarch64 -O2 before: > > > > f: > > adrp x0, .LC0 > > ldr q31, [x0, #:lo12:.LC0] > > sub v0.4s, v0.4s, v31.4s > > ret > > > > The function also needs a 16-byte constant in .rodata. > > > > After: > > > > f: > > movi v31.8h, 0xff > > add v0.4s, v0.4s, v31.4s > > ret > > > > Accept a non-stepped integral vector constant when every encoded element can > > be negated without overflow. A stepped encoding can extrapolate an > > unencoded > > signed minimum, so keep it in subtraction form. Unsigned and -fwrapv > > vectors > > already wrap and do not need an element scan. Use vector-aware predicates > > directly. Keep the integral type check before TYPE_OVERFLOW_WRAPS because > > fixed-point vectors can reach the predicate, but TYPE_OVERFLOW_WRAPS does > > not > > accept them. Keep a signed minimum element and an overflow-sanitized > > subtraction. > > > > The canonical form remains visible before dead-code elimination in one > > existing forwprop dump. Adjust its addition count. > > > > Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-pc-linux-gnu. > > Ok for trunk? > > See Andrews comments. I'll add here that for REAL_CST we attempt to > canonicalize to positive constants, so x + -5.0 -> x - 5.0 to > optimize constant pool size. Most vector constants are going to > be materialized from the constant pool as well. Not to say that > this of course should not stand in the way of canonicalization > but instead should possibly be applied late.
Just to come back to this discussion, I found the bug report which had recorded this about vectors: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92436 . Thanks, Andrea > > Richard. > > > Thanks, > > Kyrill > > > > gcc/ChangeLog: > > > > * match.pd (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/vector-sub-const-1.c: New test. > > * gcc.dg/tree-ssa/vector-sub-const-2.c: Likewise. > > > > Signed-off-by: Kyrylo Tkachov <[email protected]> > > --- > > gcc/match.pd | 27 ++++++++++-- > > gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c | 2 +- > > .../gcc.dg/tree-ssa/vector-sub-const-1.c | 43 +++++++++++++++++++ > > .../gcc.dg/tree-ssa/vector-sub-const-2.c | 12 ++++++ > > 4 files changed, 80 insertions(+), 4 deletions(-) > > 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..e41f4c19bf4 100644 > > --- a/gcc/match.pd > > +++ b/gcc/match.pd > > @@ -2428,11 +2428,32 @@ 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-stepped, 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 > > + { > > + bool negatable = (FLOAT_TYPE_P (type) > > + || (ANY_INTEGRAL_TYPE_P (type) > > + && TYPE_OVERFLOW_WRAPS (type))); > > + if (!negatable > > + && ANY_INTEGRAL_TYPE_P (type) > > + && !TYPE_OVERFLOW_SANITIZED (type) > > + && !VECTOR_CST_STEPPED_P (t)) > > + { > > + negatable = true; > > + 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/vector-sub-const-1.c > > b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c > > new file mode 100644 > > index 00000000000..56e1c146d70 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c > > @@ -0,0 +1,43 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1" } */ > > + > > +typedef __INT32_TYPE__ v4si __attribute__ ((vector_size (16))); > > +typedef __UINT32_TYPE__ v4ui __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 > > +sub_encodable (v4si x) > > +{ > > + return x - (v4si) { -16711935, -16711935, -16711935, -16711935 }; > > +} > > + > > +v4si > > +keep_min (v4si x) > > +{ > > + return x - (v4si) { -__INT32_MAX__ - 1, 1, 1, 1 }; > > +} > > + > > +v4si > > +keep_stepped_min (v4si x) > > +{ > > + return x - (v4si) ((v4ui) { 2147483644u, 2147483645u, > > + 2147483646u, 2147483647u } > > + + (v4ui) { 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 " \\+ \\{ 16711935, 16711935, > > 16711935, 16711935 \\}" 1 "forwprop1" } } */ > > +/* { dg-final { scan-tree-dump-times " - \\{ -2147483648, 1, 1, 1 \\}" 1 > > "forwprop1" } } */ > > +/* { dg-final { scan-tree-dump-times " - \\{ 2147483645, 2147483646, > > 2147483647, -2147483648 \\}" 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" } > > } */ > > > > -- > Richard Biener <[email protected]> > SUSE Software Solutions Germany GmbH, > Frankenstrasse 146, 90461 Nuernberg, Germany; > GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)
