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)
>
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.