PR middle-end/96665 - memcmp of a constant string not folded
authorMartin Sebor <msebor@redhat.com>
Tue, 18 Aug 2020 18:57:18 +0000 (12:57 -0600)
committerMartin Sebor <msebor@redhat.com>
Tue, 18 Aug 2020 18:59:09 +0000 (12:59 -0600)
Related:
PR middle-end/78257 - missing memcmp optimization with constant arrays

gcc/ChangeLog:

PR middle-end/96665
PR middle-end/78257
* expr.c (convert_to_bytes): Replace statically allocated buffer with
a dynamically allocated one of sufficient size.

gcc/testsuite/ChangeLog:

PR middle-end/96665
PR middle-end/78257
* gcc.dg/memcmp-5.c: New test.

gcc/expr.c
gcc/testsuite/gcc.dg/memcmp-5.c [new file with mode: 0644]

index dd2200ddea87324ffdd97053d4b6b1e6dcbd1986..437faeaba08030f54b26325e0747049f0be164d5 100644 (file)
@@ -11683,16 +11683,27 @@ convert_to_bytes (tree type, tree expr, vec<unsigned char> *bytes)
       return true;
     }
 
-  unsigned char charbuf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
-  int len = native_encode_expr (expr, charbuf, sizeof charbuf, 0);
-  if (len <= 0)
+  /* Except for RECORD_TYPE which may have an initialized flexible array
+     member, the size of a type is the same as the size of the initializer
+     (including any implicitly zeroed out members and padding).  Allocate
+     just enough for that many bytes.  */
+  tree expr_size = TYPE_SIZE_UNIT (TREE_TYPE (expr));
+  if (!expr_size || !tree_fits_uhwi_p (expr_size))
+    return false;
+  const unsigned HOST_WIDE_INT expr_bytes = tree_to_uhwi (expr_size);
+  const unsigned bytes_sofar = bytes->length ();
+  /* native_encode_expr can convert at most INT_MAX bytes.  vec is limited
+     to at most UINT_MAX.  */
+  if (bytes_sofar + expr_bytes > INT_MAX)
     return false;
 
-  unsigned n = bytes->length ();
-  bytes->safe_grow (n + len);
-  unsigned char *p = bytes->address ();
-  memcpy (p + n, charbuf, len);
-  return true;
+  /* Unlike for RECORD_TYPE, there is no need to clear the memory since
+     it's completely overwritten by native_encode_expr.  */
+  bytes->safe_grow (bytes_sofar + expr_bytes);
+  unsigned char *pnext = bytes->begin () + bytes_sofar;
+  int nbytes = native_encode_expr (expr, pnext, expr_bytes, 0);
+  /* NBYTES is zero on failure.  Otherwise it should equal EXPR_BYTES.  */
+  return (unsigned HOST_WIDE_INT) nbytes == expr_bytes;
 }
 
 /* Return a STRING_CST corresponding to ARG's constant initializer either
diff --git a/gcc/testsuite/gcc.dg/memcmp-5.c b/gcc/testsuite/gcc.dg/memcmp-5.c
new file mode 100644 (file)
index 0000000..34bae92
--- /dev/null
@@ -0,0 +1,72 @@
+/* PR middle-end/78257 - missing memcmp optimization with constant arrays
+   { dg-do compile }
+   { dg-options "-O -Wall -fdump-tree-optimized" } */
+
+#define A "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0"
+
+const char a257[sizeof A - 1] = A;
+const char a258[sizeof A] = A;
+
+_Static_assert (sizeof A == 258);
+_Static_assert (sizeof a257 == 257);
+
+/* Verify that initializers longer than 256 characters (an internal limit
+   on the size of a buffer used to store representations in) are handled.  */
+
+void eq_256plus (void)
+{
+  int n = 0;
+
+  n += __builtin_memcmp (a257,       A,       sizeof a257);
+  n += __builtin_memcmp (a257 +   1, A +   1, sizeof a257 - 1);
+  n += __builtin_memcmp (a257 +   2, A +   2, sizeof a257 - 2);
+  n += __builtin_memcmp (a257 + 127, A + 127, sizeof a257 - 127);
+  n += __builtin_memcmp (a257 + 128, A + 128, sizeof a257 - 128);
+  n += __builtin_memcmp (a257 + 255, A + 255, 2);
+  n += __builtin_memcmp (a257 + 256, A + 256, 1);
+
+  n += __builtin_memcmp (a258,       A,       sizeof a257);
+  n += __builtin_memcmp (a258 +   1, A +   1, sizeof a257 - 1);
+  n += __builtin_memcmp (a258 +   2, A +   2, sizeof a257 - 2);
+  n += __builtin_memcmp (a258 + 127, A + 127, sizeof a257 - 127);
+  n += __builtin_memcmp (a258 + 128, A + 128, sizeof a257 - 128);
+  n += __builtin_memcmp (a258 + 256, A + 256, 2);
+  n += __builtin_memcmp (a258 + 257, A + 257, 1);
+
+  if (n)
+    __builtin_abort ();
+}
+
+#define X "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
+          "1"
+
+void lt_256plus (void)
+{
+  int n = 0;
+
+  n += 0 >  __builtin_memcmp (a257,       X,       sizeof a257);
+  n += 0 >  __builtin_memcmp (a257 +   1, X +   1, sizeof a257 - 1);
+  n += 0 >  __builtin_memcmp (a257 +   2, X +   2, sizeof a257 - 2);
+  n += 0 >  __builtin_memcmp (a257 + 127, X + 127, sizeof a257 - 127);
+  n += 0 >  __builtin_memcmp (a257 + 128, X + 128, sizeof a257 - 128);
+  n += 0 >  __builtin_memcmp (a257 + 255, X + 255, 2);
+  n += 0 >  __builtin_memcmp (a257 + 256, X + 256, 1);
+
+  n += 0 >  __builtin_memcmp (a258,       X,       sizeof a258);
+  n += 0 >  __builtin_memcmp (a258 +   1, X +   1, sizeof a258 - 1);
+  n += 0 >  __builtin_memcmp (a258 +   2, X +   2, sizeof a258 - 2);
+  n += 0 >  __builtin_memcmp (a258 + 127, X + 127, sizeof a257 - 127);
+  n += 0 >  __builtin_memcmp (a258 + 128, X + 128, sizeof a257 - 128);
+  n += 0 >  __builtin_memcmp (a258 + 256, X + 256, 2);
+  n += 0 == __builtin_memcmp (a258 + 257, X + 257, 1);
+
+  if (n != 14)
+    __builtin_abort ();
+}