Re: [PATCH 1/3] fold-const: do not fold unsafe stepped vector negations
Andrea Pinski <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcBb2ngiZ1U02iX_uoaaWo9chjPgTNzcpCkLkAtjbn1V1Q@mail.gmail.com> |
On Wed, Aug 19, 2026 at 10:32 PM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > A VECTOR_CST can encode a stepped series without storing every lane. The > fold-const negate_expr_p checks only the encoded elements. It can therefore > approve a signed vector whose implicit final lane is INT_MIN. > > typedef int v4si __attribute__ ((vector_size (16))); > > const v4si c = { 2147483645, 2147483646, 2147483647, > (-2147483647 - 1) }; > > v4si f (v4si x) { return (-x) - c; } > v4si g (v4si x) { return -(x + c); } > v4si h () { return -c; } > > The old predicate lets f and g negate c. It represents -INT_MIN as INT_MIN, > which adds a false signed overflow for defined inputs. fold_negate_expr_1 > can also negate the encoded elements of c directly. This removes the > required overflow diagnostic from h when overflow is instrumented. > > aarch64 -O2 -fsanitize=signed-integer-overflow > -fsanitize-trap=signed-integer-overflow before: > > h: > adrp x0, .LANCHOR0 > ldr q0, [x0, #:lo12:.LANCHOR0] > ret > > After: > > h: > brk #1000 > > Reject a non-wrapping integral stepped vector in negate_expr_p. Also keep a > direct stepped integral negation when sanitizer instrumentation makes overflow > observable. Guard the wrapping query with the integral lane type so > fixed-point vectors continue to use the element checks. > > The test checks that f and g do not report overflow for defined inputs. It > also checks that h reports its real INT_MIN negation. > > Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-pc-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > gcc/ChangeLog: > > * fold-const.cc (negate_expr_p): Reject non-wrapping stepped vector > constants. > (fold_negate_expr_1): Preserve sanitized stepped integral negations. > > gcc/testsuite/ChangeLog: > > * g++.dg/ubsan/fold-negate-vector-1.C: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/fold-const.cc | 13 +++++- > .../g++.dg/ubsan/fold-negate-vector-1.C | 46 +++++++++++++++++++ > 2 files changed, 57 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/ubsan/fold-negate-vector-1.C > > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc > index 420e3185a2a..b23bbb6f9b3 100644 > --- a/gcc/fold-const.cc > +++ b/gcc/fold-const.cc > @@ -406,10 +406,15 @@ negate_expr_p (tree t) > > case VECTOR_CST: > { > - if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type)) > + tree etype = TREE_TYPE (type); > + if (FLOAT_TYPE_P (etype) > + || (INTEGRAL_TYPE_P (etype) && TYPE_OVERFLOW_WRAPS (type))) > return true; This should just be: if (FLOAT_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type)) return true; > > - /* Steps don't prevent negation. */ > + /* An implicit element of a stepped vector can be the minimum > + value. */ > + if (VECTOR_CST_STEPPED_P (t)) > + return false; > unsigned int count = vector_cst_encoded_nelts (t); > for (unsigned int i = 0; i < count; ++i) > if (!negate_expr_p (VECTOR_CST_ENCODED_ELT (t, i))) > @@ -566,6 +571,10 @@ fold_negate_expr_1 (location_t loc, tree t) > > case VECTOR_CST: > { > + if (VECTOR_CST_STEPPED_P (t) > + && TYPE_OVERFLOW_SANITIZED (TREE_TYPE (type))) && TYPE_OVERFLOW_SANITIZED (type)) No reason to take the element type here. Rather TYPE_OVERFLOW_SANITIZED should be changed to use ANY_INTEGRAL_TYPE_P . BUT submit that separately. > + return NULL_TREE; > + > tree_vector_builder elts; > elts.new_unary_operation (type, t, true); > unsigned int count = elts.encoded_nelts (); > diff --git a/gcc/testsuite/g++.dg/ubsan/fold-negate-vector-1.C b/gcc/testsuite/g++.dg/ubsan/fold-negate-vector-1.C > new file mode 100644 > index 00000000000..cda0fd9817f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ubsan/fold-negate-vector-1.C > @@ -0,0 +1,46 @@ > +// { dg-do run { target int32 } } > +// { dg-options "-O2 -Wno-psabi -fsanitize=signed-integer-overflow" } > + > +#define INT_MAX __INT_MAX__ > +#define INT_MIN (-INT_MAX - 1) > + > +typedef int v4si __attribute__ ((vector_size (16))); > + > +const v4si c = { INT_MAX - 2, INT_MAX - 1, INT_MAX, INT_MIN }; > + > +v4si __attribute__ ((noipa)) > +f (v4si x) > +{ > + return (-x) - c; > +} > + > +v4si __attribute__ ((noipa)) > +g (v4si x) > +{ > + return -(x + c); > +} > + > +v4si __attribute__ ((noipa)) > +h () > +{ > + return -c; > +} > + > +int > +main () > +{ > + v4si x = { 0, 0, 0, 1 }; > + v4si y = f (x); > + if (y[3] != INT_MAX) > + __builtin_abort (); > + > + y = g (x); > + if (y[3] != INT_MAX) > + __builtin_abort (); > + > + volatile v4si z = h (); > + if (z[3] != INT_MIN) > + __builtin_abort (); > +} > + > +// { dg-output "negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself" } > -- > 2.50.1 (Apple Git-155) >