Re: [PATCH 1/3] fold-const: do not fold unsafe stepped vector negations
Kyrylo Tkachov <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
> On 20 Aug 2026, at 10:41, Richard Biener <[email protected]> wrote: > > On Thu, Aug 20, 2026 at 7:33 AM <[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; >> >> - /* Steps don't prevent negation. */ >> + /* An implicit element of a stepped vector can be the minimum >> + value. */ >> + if (VECTOR_CST_STEPPED_P (t)) > > why unconditional here > >> + 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))) > > but conditional on TYPE_OVERFLOW_SANITIZED here? I’ve added a comment in the commit message for the respin that I’ve just sent out, now patch 2/4. Thanks, Kyrill > >> + 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)