[PATCH 1/3] fold-const: do not fold unsafe stepped vector negations

<[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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))
+	  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)))
+	  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.