summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.dg')
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-1.c47
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-10.c80
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-11.c70
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-12.c90
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-12g.c6
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-13.c68
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-14g.c115
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-14gf.c24
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-15.c60
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-16g.c34
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-17g.c57
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-18g.c82
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-19.c81
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-1f.c18
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-2.c49
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-20.c95
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-2f.c18
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-3.c66
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-4.c75
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-4g.c14
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-4gf.c19
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-5.c57
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-6.c86
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-7.c53
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-8.c52
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-9.c109
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt.h59
27 files changed, 1584 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/strlenopt-1.c b/gcc/testsuite/gcc.dg/strlenopt-1.c
new file mode 100644
index 00000000000..5bc4f0cd176
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-1.c
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+foo (char *p, char *r)
+{
+ char *q = malloc (strlen (p) + strlen (r) + 64);
+ if (q == NULL) return NULL;
+ /* This strcpy can be optimized into memcpy, using the remembered
+ strlen (p). */
+ strcpy (q, p);
+ /* These two strcat can be optimized into memcpy. The first one
+ could be even optimized into a *ptr = '/'; store as the '\0'
+ is immediately overwritten. */
+ strcat (q, "/");
+ strcat (q, "abcde");
+ /* Due to inefficient PTA (PR50262) the above calls invalidate
+ string length of r, so it is optimized just into strcpy instead
+ of memcpy. */
+ strcat (q, r);
+ return q;
+}
+
+int
+main ()
+{
+ char *volatile p = "string1";
+ char *volatile r = "string2";
+ char *q = foo (p, r);
+ if (q != NULL)
+ {
+ if (strcmp (q, "string1/abcdestring2"))
+ abort ();
+ free (q);
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-10.c b/gcc/testsuite/gcc.dg/strlenopt-10.c
new file mode 100644
index 00000000000..a18c06ae069
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-10.c
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) size_t
+fn1 (char *p)
+{
+ char *q;
+ /* This can be optimized into memcpy and the size can be decreased to one,
+ as it is immediately overwritten. */
+ strcpy (p, "z");
+ q = strchr (p, '\0');
+ *q = 32;
+ /* This strlen can't be optimized away, string length is unknown here. */
+ return strlen (p);
+}
+
+__attribute__((noinline, noclone)) void
+fn2 (char *p, const char *z, size_t *lp)
+{
+ char *q, *r;
+ char buf[64];
+ size_t l[10];
+ /* The first strlen stays, all the strcpy calls can be optimized
+ into memcpy and all other strlen calls and all strchr calls
+ optimized away. */
+ l[0] = strlen (z);
+ strcpy (buf, z);
+ strcpy (p, "abcde");
+ q = strchr (p, '\0');
+ strcpy (q, "efghi");
+ r = strchr (q, '\0');
+ strcpy (r, "jkl");
+ l[1] = strlen (p);
+ l[2] = strlen (q);
+ l[3] = strlen (r);
+ strcpy (r, buf);
+ l[4] = strlen (p);
+ l[5] = strlen (q);
+ l[6] = strlen (r);
+ strcpy (r, "mnopqr");
+ l[7] = strlen (p);
+ l[8] = strlen (q);
+ l[9] = strlen (r);
+ memcpy (lp, l, sizeof l);
+}
+
+int
+main ()
+{
+ char buf[64];
+ size_t l[10];
+ const char *volatile z = "ABCDEFG";
+ memset (buf, '\0', sizeof buf);
+ if (fn1 (buf) != 2 || buf[0] != 'z' || buf[1] != 32 || buf[2] != '\0')
+ abort ();
+ fn2 (buf, z, l);
+ if (memcmp (buf, "abcdeefghimnopqr", 17) != 0)
+ abort ();
+ if (l[0] != 7)
+ abort ();
+ if (l[1] != 13 || l[2] != 8 || l[3] != 3)
+ abort ();
+ if (l[4] != 17 || l[5] != 12 || l[6] != 7)
+ abort ();
+ if (l[7] != 16 || l[8] != 11 || l[9] != 6)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-11.c b/gcc/testsuite/gcc.dg/strlenopt-11.c
new file mode 100644
index 00000000000..03f8790d0c6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-11.c
@@ -0,0 +1,70 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) void
+fn1 (char *p, const char *z, size_t *lp)
+{
+ char *q, *r, *s;
+ char buf[64];
+ size_t l[11];
+ /* The first strlen stays, all the strcpy calls can be optimized
+ into memcpy and most other strlen calls and all strchr calls
+ optimized away. l[6] = strlen (r); and l[9] = strlen (r); need
+ to stay, because we need to invalidate the knowledge about
+ r strlen after strcpy (q, "jklmnopqrst"). */
+ l[0] = strlen (z);
+ strcpy (buf, z);
+ strcpy (p, "abcde");
+ q = strchr (p, '\0');
+ strcpy (q, "efghi");
+ r = strchr (q, '\0');
+ strcpy (r, buf);
+ l[1] = strlen (p);
+ l[2] = strlen (q);
+ l[3] = strlen (r);
+ strcpy (q, "jklmnopqrst");
+ l[4] = strlen (p);
+ l[5] = strlen (q);
+ l[6] = strlen (r);
+ s = strchr (q, '\0');
+ strcpy (s, buf);
+ l[7] = strlen (p);
+ l[8] = strlen (q);
+ l[9] = strlen (r);
+ l[10] = strlen (s);
+ memcpy (lp, l, sizeof l);
+}
+
+int
+main ()
+{
+ char buf[64];
+ size_t l[11];
+ const char *volatile z = "ABCDEFG";
+ memset (buf, '\0', sizeof buf);
+ fn1 (buf, z, l);
+ if (memcmp (buf, "abcdejklmnopqrstABCDEFG", 24) != 0)
+ abort ();
+ if (l[0] != 7)
+ abort ();
+ if (l[1] != 17 || l[2] != 12 || l[3] != 7)
+ abort ();
+ if (l[4] != 16 || l[5] != 11 || l[6] != 6)
+ abort ();
+ if (l[7] != 23 || l[8] != 18 || l[9] != 13 || l[10] != 7)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.9. = " 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-12.c b/gcc/testsuite/gcc.dg/strlenopt-12.c
new file mode 100644
index 00000000000..1005fc6709e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-12.c
@@ -0,0 +1,90 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (char *p, size_t *l)
+{
+ char *q = strcat (p, "abcde");
+ *l = strlen (p);
+ return q;
+}
+
+__attribute__((noinline, noclone)) char *
+fn2 (char *p, const char *q, size_t *l1, size_t *l2)
+{
+ size_t l = strlen (q);
+ char *r = strcat (p, q);
+ *l1 = l;
+ *l2 = strlen (p);
+ return r;
+}
+
+__attribute__((noinline, noclone)) char *
+fn3 (char *p, const char *q, size_t *l)
+{
+ char *r = strcpy (p, q);
+ *l = strlen (p);
+ return r;
+}
+
+__attribute__((noinline, noclone)) char *
+fn4 (char *p, const char *q, size_t *l)
+{
+ char *r = strcat (p, q);
+ *l = strlen (p);
+ return r;
+}
+
+__attribute__((noinline, noclone)) char *
+fn5 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
+{
+ size_t l = strlen (q);
+ size_t ll = strlen (p);
+ char *r = strcat (p, q);
+ *l1 = l;
+ *l2 = strlen (p);
+ *l3 = ll;
+ return r;
+}
+
+__attribute__((noinline, noclone)) char *
+fn6 (char *p, const char *q, size_t *l1, size_t *l2)
+{
+ size_t l = strlen (p);
+ char *r = strcat (p, q);
+ *l1 = strlen (p);
+ *l2 = l;
+ return r;
+}
+
+int
+main ()
+{
+ char buf[64];
+ const char *volatile q = "fgh";
+ size_t l, l1, l2, l3;
+ memset (buf, '\0', sizeof buf);
+ memset (buf, 'a', 3);
+ if (fn1 (buf, &l) != buf || l != 8 || memcmp (buf, "aaaabcde", 9) != 0)
+ abort ();
+ if (fn2 (buf, q, &l1, &l2) != buf || l1 != 3 || l2 != 11
+ || memcmp (buf, "aaaabcdefgh", 12) != 0)
+ abort ();
+ if (fn3 (buf, q, &l) != buf || l != 3
+ || memcmp (buf, "fgh\0bcdefgh", 12) != 0)
+ abort ();
+ if (fn4 (buf, q, &l) != buf || l != 6
+ || memcmp (buf, "fghfgh\0efgh", 12) != 0)
+ abort ();
+ l1 = 0;
+ l2 = 0;
+ if (fn5 (buf, q, &l1, &l2, &l3) != buf || l1 != 3 || l2 != 9 || l3 != 6
+ || memcmp (buf, "fghfghfgh\0h", 12) != 0)
+ abort ();
+ if (fn6 (buf, q, &l1, &l2) != buf || l1 != 12 || l2 != 9
+ || memcmp (buf, "fghfghfghfgh", 13) != 0)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/strlenopt-12g.c b/gcc/testsuite/gcc.dg/strlenopt-12g.c
new file mode 100644
index 00000000000..2b6508f01d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-12g.c
@@ -0,0 +1,6 @@
+/* This test needs runtime that provides stpcpy function. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2" } */
+
+#define USE_GNU
+#include "strlenopt-12.c"
diff --git a/gcc/testsuite/gcc.dg/strlenopt-13.c b/gcc/testsuite/gcc.dg/strlenopt-13.c
new file mode 100644
index 00000000000..62effcd64d0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-13.c
@@ -0,0 +1,68 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) void
+fn1 (char *p, const char *y, const char *z, size_t *lp)
+{
+ char *q, *r, *s;
+ char buf1[64], buf2[64];
+ size_t l[8];
+ /* These two strlen calls stay, all strcpy calls are optimized into
+ memcpy, all strchr calls optimized away, and most other strlen
+ calls too. */
+ l[0] = strlen (y);
+ l[1] = strlen (z);
+ strcpy (buf1, y);
+ strcpy (buf2, z);
+ strcpy (p, "abcde");
+ q = strchr (p, '\0');
+ strcpy (q, "efghi");
+ r = strchr (q, '\0');
+ strcpy (r, buf1);
+ l[2] = strlen (p);
+ l[3] = strlen (q);
+ l[4] = strlen (r);
+ strcpy (r, buf2);
+ /* Except for these two calls, strlen (r) before and after the above
+ is non-constant, so adding l[4] - l[1] to all previous strlens
+ might make the expressions already too complex. */
+ l[5] = strlen (p);
+ l[6] = strlen (q);
+ /* This one is of course optimized, it is l[1]. */
+ l[7] = strlen (r);
+ memcpy (lp, l, sizeof l);
+}
+
+int
+main ()
+{
+ char buf[64];
+ size_t l[8];
+ const char *volatile y = "ABCDEFG";
+ const char *volatile z = "HIJK";
+ memset (buf, '\0', sizeof buf);
+ fn1 (buf, y, z, l);
+ if (memcmp (buf, "abcdeefghiHIJK", 15) != 0)
+ abort ();
+ if (l[0] != 7 || l[1] != 4)
+ abort ();
+ if (l[2] != 17 || l[3] != 12 || l[4] != 7)
+ abort ();
+ if (l[5] != 14 || l[6] != 9 || l[7] != 4)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.1. = " 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.5. = " 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-14g.c b/gcc/testsuite/gcc.dg/strlenopt-14g.c
new file mode 100644
index 00000000000..62a120de07b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-14g.c
@@ -0,0 +1,115 @@
+/* This test needs runtime that provides stpcpy and mempcpy functions. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (char *p, size_t *l1, size_t *l2)
+{
+ char *a = mempcpy (p, "abcde", 6);
+ /* This strlen needs to stay. */
+ size_t la = strlen (a);
+ /* This strlen can be optimized into 5. */
+ size_t lp = strlen (p);
+ *l1 = la;
+ *l2 = lp;
+ return a;
+}
+
+__attribute__((noinline, noclone)) char *
+fn2 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
+{
+ /* This strlen needs to stay. */
+ size_t lq = strlen (q);
+ char *a = mempcpy (p, q, lq + 1);
+ /* This strlen needs to stay. */
+ size_t la = strlen (a);
+ /* This strlen can be optimized into lq. */
+ size_t lp = strlen (p);
+ *l1 = lq;
+ *l2 = la;
+ *l3 = lp;
+ return a;
+}
+
+__attribute__((noinline, noclone)) char *
+fn3 (char *p, size_t *l1, size_t *l2)
+{
+ char *a = stpcpy (p, "abcde");
+ /* This strlen can be optimized into 0. */
+ size_t la = strlen (a);
+ /* This strlen can be optimized into 5. */
+ size_t lp = strlen (p);
+ *l1 = la;
+ *l2 = lp;
+ return a;
+}
+
+__attribute__((noinline, noclone)) char *
+fn4 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
+{
+ /* This strlen needs to stay. */
+ size_t lq = strlen (q);
+ char *a = stpcpy (p, q);
+ /* This strlen can be optimized into 0. */
+ size_t la = strlen (a);
+ /* This strlen can be optimized into lq. */
+ size_t lp = strlen (p);
+ *l1 = lq;
+ *l2 = la;
+ *l3 = lp;
+ return a;
+}
+
+__attribute__((noinline, noclone)) char *
+fn5 (char *p, const char *q, size_t *l1, size_t *l2)
+{
+ char *a = stpcpy (p, q);
+ /* This strlen can be optimized into 0. */
+ size_t la = strlen (a);
+ /* This strlen can be optimized into a - p. */
+ size_t lp = strlen (p);
+ *l1 = la;
+ *l2 = lp;
+ return a;
+}
+
+int
+main ()
+{
+ char buf[64];
+ const char *volatile q = "ABCDEFGH";
+ size_t l1, l2, l3;
+ memset (buf, '\0', sizeof buf);
+ memset (buf + 6, 'z', 7);
+ if (fn1 (buf, &l1, &l2) != buf + 6 || l1 != 7 || l2 != 5
+ || memcmp (buf, "abcde\0zzzzzzz", 14) != 0)
+ abort ();
+ if (fn2 (buf, q, &l1, &l2, &l3) != buf + 9 || l1 != 8 || l2 != 4 || l3 != 8
+ || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
+ abort ();
+ if (fn3 (buf, &l1, &l2) != buf + 5 || l1 != 0 || l2 != 5
+ || memcmp (buf, "abcde\0GH\0zzzz", 14) != 0)
+ abort ();
+ l3 = 0;
+ memset (buf, 'n', 9);
+ if (fn4 (buf, q, &l1, &l2, &l3) != buf + 8 || l1 != 8 || l2 != 0 || l3 != 8
+ || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
+ abort ();
+ memset (buf, 'm', 9);
+ if (fn5 (buf, q, &l1, &l2) != buf + 8 || l1 != 0 || l2 != 8
+ || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-14gf.c b/gcc/testsuite/gcc.dg/strlenopt-14gf.c
new file mode 100644
index 00000000000..999759e86f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-14gf.c
@@ -0,0 +1,24 @@
+/* This test needs runtime that provides stpcpy, mempcpy and __*_chk
+ functions. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define FORTIFY_SOURCE 2
+#include "strlenopt-14g.c"
+
+/* Compared to strlenopt-14gf.c, strcpy_chk with string literal as
+ second argument isn't being optimized by builtins.c into
+ memcpy. */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-15.c b/gcc/testsuite/gcc.dg/strlenopt-15.c
new file mode 100644
index 00000000000..495166ddb9b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-15.c
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) size_t
+fn1 (char *p, size_t l)
+{
+ memcpy (p, "abcdef", l);
+ /* This strlen can't be optimized, as l is unknown. */
+ return strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn2 (char *p, const char *q, size_t *lp)
+{
+ size_t l = strlen (q), l2;
+ memcpy (p, q, 7);
+ /* This strlen can't be optimized, as l might be bigger than 7. */
+ l2 = strlen (p);
+ *lp = l;
+ return l2;
+}
+
+__attribute__((noinline, noclone)) char *
+fn3 (char *p)
+{
+ *p = 0;
+ return p + 1;
+}
+
+int
+main ()
+{
+ char buf[64];
+ const char *volatile q = "ABCDEFGH";
+ const char *volatile q2 = "IJ\0KLMNOPQRS";
+ size_t l;
+ memset (buf, '\0', sizeof buf);
+ memset (buf + 2, 'a', 7);
+ if (fn1 (buf, 3) != 9 || memcmp (buf, "abcaaaaaa", 10) != 0)
+ abort ();
+ if (fn1 (buf, 7) != 6 || memcmp (buf, "abcdef\0aa", 10) != 0)
+ abort ();
+ if (fn2 (buf, q, &l) != 9 || l != 8 || memcmp (buf, "ABCDEFGaa", 10) != 0)
+ abort ();
+ if (fn2 (buf, q2, &l) != 2 || l != 2 || memcmp (buf, "IJ\0KLMNaa", 10) != 0)
+ abort ();
+ if (fn3 (buf) != buf + 1 || memcmp (buf, "\0J\0KLMNaa", 10) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-16g.c b/gcc/testsuite/gcc.dg/strlenopt-16g.c
new file mode 100644
index 00000000000..11e4d319adb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-16g.c
@@ -0,0 +1,34 @@
+/* This test needs runtime that provides stpcpy function. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (char *p, const char *q)
+{
+ /* This strcpy can be optimized into stpcpy. */
+ strcpy (p, q);
+ /* And this strchr into the return value from it. */
+ return strchr (p, '\0');
+}
+
+int
+main ()
+{
+ char buf[64];
+ const char *volatile q = "ABCDEFGH";
+ if (fn1 (buf, q) != buf + 8 || memcmp (buf, "ABCDEFGH", 9) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-17g.c b/gcc/testsuite/gcc.dg/strlenopt-17g.c
new file mode 100644
index 00000000000..b61bf74b8b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-17g.c
@@ -0,0 +1,57 @@
+/* This test needs runtime that provides stpcpy function. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) int
+foo (const char *p)
+{
+ static int c;
+ const char *q[] = { "123498765abcde", "123498765..", "129abcde", "129abcde" };
+ if (strcmp (p, q[c]) != 0)
+ abort ();
+ return c++;
+}
+
+__attribute__((noinline, noclone)) void
+bar (const char *p, const char *q)
+{
+ size_t l;
+ /* This strlen stays. */
+ char *a = __builtin_alloca (strlen (p) + 50);
+ /* strcpy can be optimized into memcpy. */
+ strcpy (a, p);
+ /* strcat into stpcpy. */
+ strcat (a, q);
+ /* This strlen can be optimized away. */
+ l = strlen (a);
+ /* This becomes memcpy. */
+ strcat (a, "abcde");
+ if (!foo (a))
+ /* And this one too. */
+ strcpy (a + l, "..");
+ foo (a);
+}
+
+int
+main ()
+{
+ const char *volatile s1 = "1234";
+ const char *volatile s2 = "98765";
+ const char *volatile s3 = "12";
+ const char *volatile s4 = "9";
+ bar (s1, s2);
+ bar (s3, s4);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-18g.c b/gcc/testsuite/gcc.dg/strlenopt-18g.c
new file mode 100644
index 00000000000..c70daea4b28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-18g.c
@@ -0,0 +1,82 @@
+/* This test needs runtime that provides stpcpy function. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (int x, int y, int z)
+{
+ static char buf[40];
+ const char *p;
+ switch (x)
+ {
+ case 0:
+ p = "abcd";
+ break;
+ case 1:
+ p = "efgh";
+ break;
+ case 2:
+ p = "ijkl";
+ break;
+ default:
+ p = "mnopq";
+ break;
+ }
+ if (y)
+ {
+ strcpy (buf, p);
+ if (z)
+ strcat (buf, "ABCDEFG");
+ else
+ strcat (buf, "HIJKLMN");
+ }
+ else
+ {
+ strcpy (buf, p + 1);
+ if (z)
+ strcat (buf, "OPQ");
+ else
+ strcat (buf, "RST");
+ }
+ return buf;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ {
+ const char *p = "abcdefghijklmnopq" + (i < 3 ? i : 3) * 4;
+ const char *q;
+ int j = i >= 3;
+ fn1 (i ? 0 : 1, 1, 1);
+ q = fn1 (i, 0, 0);
+ if (memcmp (q, p + 1, 3 + j) != 0 || memcmp (q + 3 + j, "RST", 4) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 0, 1);
+ q = fn1 (i, 1, 0);
+ if (memcmp (q, p, 4 + j) != 0 || memcmp (q + 4 + j, "HIJKLMN", 8) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 1, 0);
+ q = fn1 (i, 0, 1);
+ if (memcmp (q, p + 1, 3 + j) != 0 || memcmp (q + 3 + j, "OPQ", 4) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 0, 0);
+ q = fn1 (i, 1, 1);
+ if (memcmp (q, p, 4 + j) != 0 || memcmp (q + 4 + j, "ABCDEFG", 8) != 0)
+ abort ();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-19.c b/gcc/testsuite/gcc.dg/strlenopt-19.c
new file mode 100644
index 00000000000..042fd77b002
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-19.c
@@ -0,0 +1,81 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (int x, int y, int z)
+{
+ static char buf[40];
+ const char *p;
+ switch (x)
+ {
+ case 0:
+ p = "abcd";
+ /* Prevent cswitch optimization. */
+ asm volatile ("" : : : "memory");
+ break;
+ case 1:
+ p = "efgh";
+ break;
+ case 2:
+ p = "ijkl";
+ break;
+ default:
+ p = "mnop";
+ break;
+ }
+ if (y)
+ {
+ strcpy (buf, p);
+ if (z)
+ strcat (buf, "ABCDEFG");
+ else
+ strcat (buf, "HIJKLMN");
+ }
+ else
+ {
+ strcpy (buf, p + 1);
+ if (z)
+ strcat (buf, "OPQ");
+ else
+ strcat (buf, "RST");
+ }
+ return buf;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ {
+ const char *p = "abcdefghijklmnop" + (i < 3 ? i : 3) * 4;
+ const char *q;
+ fn1 (i ? 0 : 1, 1, 1);
+ q = fn1 (i, 0, 0);
+ if (memcmp (q, p + 1, 3) != 0 || memcmp (q + 3, "RST", 4) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 0, 1);
+ q = fn1 (i, 1, 0);
+ if (memcmp (q, p, 4) != 0 || memcmp (q + 4, "HIJKLMN", 8) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 1, 0);
+ q = fn1 (i, 0, 1);
+ if (memcmp (q, p + 1, 3) != 0 || memcmp (q + 3, "OPQ", 4) != 0)
+ abort ();
+ fn1 (i ? 0 : 1, 0, 0);
+ q = fn1 (i, 1, 1);
+ if (memcmp (q, p, 4) != 0 || memcmp (q + 4, "ABCDEFG", 8) != 0)
+ abort ();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-1f.c b/gcc/testsuite/gcc.dg/strlenopt-1f.c
new file mode 100644
index 00000000000..4b0207fd4f7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-1f.c
@@ -0,0 +1,18 @@
+/* This test needs runtime that provides __*_chk functions. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define FORTIFY_SOURCE 2
+#include "strlenopt-1.c"
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-2.c b/gcc/testsuite/gcc.dg/strlenopt-2.c
new file mode 100644
index 00000000000..5e6557b5687
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-2.c
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+foo (char *p, char *r)
+{
+ char buf[26];
+ if (strlen (p) + strlen (r) + 9 > 26)
+ return NULL;
+ /* This strcpy can be optimized into memcpy, using the remembered
+ strlen (p). */
+ strcpy (buf, p);
+ /* These two strcat can be optimized into memcpy. The first one
+ could be even optimized into a *ptr = '/'; store as the '\0'
+ is immediately overwritten. */
+ strcat (buf, "/");
+ strcat (buf, "abcde");
+ /* This strcpy can be optimized into memcpy, using the remembered
+ strlen (r). */
+ strcat (buf, r);
+ /* And this can be optimized into memcpy too. */
+ strcat (buf, "fg");
+ return strdup (buf);
+}
+
+int
+main ()
+{
+ char *volatile p = "string1";
+ char *volatile r = "string2";
+ char *q = foo (p, r);
+ if (q != NULL)
+ {
+ if (strcmp (q, "string1/abcdestring2fg"))
+ abort ();
+ free (q);
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-20.c b/gcc/testsuite/gcc.dg/strlenopt-20.c
new file mode 100644
index 00000000000..6fe99a422e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-20.c
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) const char *
+fn1 (int x, int y)
+{
+ const char *p;
+ switch (x)
+ {
+ case 0:
+ p = "abcd";
+ /* Prevent cswitch optimization. */
+ asm volatile ("" : : : "memory");
+ break;
+ case 1:
+ p = "efgh";
+ break;
+ case 2:
+ p = "ijkl";
+ break;
+ default:
+ p = "mnop";
+ break;
+ }
+ if (y)
+ /* strchr should be optimized into p + 4 here. */
+ return strchr (p, '\0');
+ else
+ /* and strlen into 3. */
+ return p + strlen (p + 1);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn2 (char *p, char *q)
+{
+ size_t l;
+ /* Both strcpy calls can be optimized into memcpy, strlen needs to stay. */
+ strcpy (p, "abc");
+ p[3] = 'd';
+ l = strlen (p);
+ strcpy (q, p);
+ return l;
+}
+
+__attribute__((noinline, noclone)) char *
+fn3 (char *p)
+{
+ char *c;
+ /* The strcpy call can be optimized into memcpy, strchr needs to stay,
+ strcat is optimized into memcpy. */
+ strcpy (p, "abc");
+ p[3] = 'd';
+ c = strchr (p, '\0');
+ strcat (p, "efgh");
+ return c;
+}
+
+int
+main ()
+{
+ int i;
+ char buf[64], buf2[64];
+ for (i = 0; i < 5; i++)
+ {
+ const char *p = "abcdefghijklmnop" + (i < 3 ? i : 3) * 4;
+ const char *q;
+ q = fn1 (i, 1);
+ if (memcmp (q - 4, p, 4) != 0 || q[0] != '\0')
+ abort ();
+ q = fn1 (i, 0);
+ if (memcmp (q - 3, p, 4) != 0 || q[1] != '\0')
+ abort ();
+ }
+ memset (buf, '\0', sizeof buf);
+ memset (buf + 4, 'z', 2);
+ if (fn2 (buf, buf2) != 6
+ || memcmp (buf, "abcdzz", 7) != 0
+ || memcmp (buf2, "abcdzz", 7) != 0)
+ abort ();
+ memset (buf, '\0', sizeof buf);
+ memset (buf + 4, 'z', 2);
+ if (fn3 (buf) != buf + 6 || memcmp (buf, "abcdzzefgh", 11) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-2f.c b/gcc/testsuite/gcc.dg/strlenopt-2f.c
new file mode 100644
index 00000000000..7996e67618c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-2f.c
@@ -0,0 +1,18 @@
+/* This test needs runtime that provides __*_chk functions. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define FORTIFY_SOURCE 2
+#include "strlenopt-2.c"
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-3.c b/gcc/testsuite/gcc.dg/strlenopt-3.c
new file mode 100644
index 00000000000..1bab8f37e99
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-3.c
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) size_t
+fn1 (char *p, char *q)
+{
+ size_t s = strlen (q);
+ strcpy (p, q);
+ return s - strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn2 (char *p, char *q)
+{
+ size_t s = strlen (q);
+ memcpy (p, q, s + 1);
+ return s - strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn3 (char *p)
+{
+ memcpy (p, "abcd", 5);
+ return strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn4 (char *p)
+{
+ memcpy (p, "efg\0hij", 6);
+ return strlen (p);
+}
+
+int
+main ()
+{
+ char buf[64];
+ char *volatile p = buf;
+ char *volatile q = "ABCDEF";
+ buf[7] = 'G';
+ if (fn1 (p, q) != 0 || memcmp (buf, "ABCDEF\0G", 8))
+ abort ();
+ q = "HIJ";
+ if (fn2 (p + 1, q) != 0 || memcmp (buf, "AHIJ\0F\0G", 8))
+ abort ();
+ buf[6] = 'K';
+ if (fn3 (p + 1) != 4 || memcmp (buf, "Aabcd\0KG", 8))
+ abort ();
+ if (fn4 (p) != 3 || memcmp (buf, "efg\0hiKG", 8))
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
+/* { dg-final { scan-tree-dump-times "return 0" 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "return 4" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "return 3" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-4.c b/gcc/testsuite/gcc.dg/strlenopt-4.c
new file mode 100644
index 00000000000..beea4959245
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-4.c
@@ -0,0 +1,75 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+/* If stpcpy can't be used, this is optimized into
+ strcpy (p, q); strcat (p, r); memcpy (p + strlen (p), "abcd", 5);
+ If stpcpy can be used (see strlenopt-4g.c test),
+ this is optimized into
+ memcpy (stpcpy (stpcpy (p, q), r), "abcd", 5); */
+__attribute__((noinline, noclone)) void
+foo (char *p, const char *q, const char *r)
+{
+ strcpy (p, q);
+ strcat (p, r);
+ strcat (p, "abcd");
+}
+
+/* If stpcpy can't be used, this is optimized into
+ memcpy (p, "abcd", 4); strcpy (p + 4, q); strcat (p, r);
+ If stpcpy can be used, this is optimized into
+ memcpy (p, "abcd", 4); strcpy (stpcpy (p + 4, q), r); */
+__attribute__((noinline, noclone)) void
+bar (char *p, const char *q, const char *r)
+{
+ strcpy (p, "abcd");
+ strcat (p, q);
+ strcat (p, r);
+}
+
+/* If stpcpy can't be used, this is optimized into
+ strcat (p, q); memcpy (t1 = p + strlen (p), "abcd", 4);
+ strcpy (t1 + 4, r); memcpy (p + strlen (p), "efgh", 5);
+ If stpcpy can be used, this is optimized into
+ t1 = stpcpy (p + strlen (p), q); memcpy (t1, "abcd", 4);
+ memcpy (stpcpy (t1 + 4, r), "efgh", 5); */
+__attribute__((noinline, noclone)) void
+baz (char *p, const char *q, const char *r)
+{
+ strcat (p, q);
+ strcat (p, "abcd");
+ strcat (p, r);
+ strcat (p, "efgh");
+}
+
+char buf[64];
+
+int
+main ()
+{
+ char *volatile p = buf;
+ const char *volatile q = "ij";
+ const char *volatile r = "klmno";
+ foo (p, q, r);
+ if (memcmp (buf, "ijklmnoabcd\0\0\0\0\0\0\0\0", 20) != 0)
+ abort ();
+ memset (buf, '\0', sizeof buf);
+ bar (p, q, r);
+ if (memcmp (buf, "abcdijklmno\0\0\0\0\0\0\0\0", 20) != 0)
+ abort ();
+ memset (buf, 'v', 3);
+ memset (buf + 3, '\0', -3 + sizeof buf);
+ baz (p, q, r);
+ if (memcmp (buf, "vvvijabcdklmnoefgh\0", 20) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-4g.c b/gcc/testsuite/gcc.dg/strlenopt-4g.c
new file mode 100644
index 00000000000..7b397366e9c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-4g.c
@@ -0,0 +1,14 @@
+/* This test needs runtime that provides stpcpy function. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#include "strlenopt-4.c"
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-4gf.c b/gcc/testsuite/gcc.dg/strlenopt-4gf.c
new file mode 100644
index 00000000000..cf99212a152
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-4gf.c
@@ -0,0 +1,19 @@
+/* This test needs runtime that provides stpcpy and __*_chk functions. */
+/* { dg-do run { target *-*-linux* } } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#define USE_GNU
+#define FORTIFY_SOURCE 2
+#include "strlenopt-4.c"
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-5.c b/gcc/testsuite/gcc.dg/strlenopt-5.c
new file mode 100644
index 00000000000..131494ac8e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-5.c
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+foo (char *p, const char *q)
+{
+ char *e = strchr (p, '\0');
+ strcat (p, q);
+ return e;
+}
+
+__attribute__((noinline, noclone)) char *
+bar (char *p)
+{
+ memcpy (p, "abcd", 5);
+ return strchr (p, '\0');
+}
+
+__attribute__((noinline, noclone)) void
+baz (char *p)
+{
+ char *e = strchr (p, '\0');
+ strcat (e, "abcd");
+}
+
+char buf[64];
+
+int
+main ()
+{
+ char *volatile p = buf;
+ const char *volatile q = "ij";
+ memset (buf, 'v', 3);
+ if (foo (p, q) != buf + 3
+ || memcmp (buf, "vvvij\0\0\0\0", 10) != 0)
+ abort ();
+ memset (buf, '\0', sizeof buf);
+ if (bar (p) != buf + 4
+ || memcmp (buf, "abcd\0\0\0\0\0", 10) != 0)
+ abort ();
+ memset (buf, 'v', 2);
+ memset (buf + 2, '\0', -2 + sizeof buf);
+ baz (p);
+ if (memcmp (buf, "vvabcd\0\0\0", 10) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-6.c b/gcc/testsuite/gcc.dg/strlenopt-6.c
new file mode 100644
index 00000000000..d9b718758a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-6.c
@@ -0,0 +1,86 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+foo (char *x)
+{
+#ifdef PR50262_FIXED
+ /* Once PTA is fixed, we'll need just one strlen here,
+ without the memcpy. */
+ char *p = x;
+ char *q = malloc (strlen (p) + 64);
+#else
+ /* This is here just because PTA can't figure that
+ *q = '\0' store below can't change p's length.
+ In this case we have one strlen and one memcpy here. */
+ char b[64];
+ char *q = malloc (strlen (x) + 64);
+ char *p = strcpy (b, x);
+#endif
+ char *r;
+ if (q == NULL) return NULL;
+ /* This store can be optimized away once strcat is
+ replaced with memcpy. */
+ *q = '\0';
+ /* These two strcat calls can be optimized into memcpy calls. */
+ strcat (q, p);
+ strcat (q, "/");
+ /* The strchr can be optimized away, as we know the current
+ string length as well as end pointer. */
+ r = strchr (q, '\0');
+ /* This store can go, as it is overwriting '\0' with the same
+ character. */
+ *r = '\0';
+ /* And this strcat can be again optimized into memcpy call. */
+ strcat (q, "abcde");
+ return q;
+}
+
+__attribute__((noinline, noclone)) char *
+bar (char *p)
+{
+ char buf[26];
+ char *r;
+ if (strlen (p) + 9 > 26)
+ return NULL;
+ *buf = '\0';
+ strcat (buf, p);
+ strcat (buf, "/");
+ r = strchr (buf, '\0');
+ *r = '\0';
+ strcat (buf, "abcde");
+ return strdup (buf);
+}
+
+int
+main ()
+{
+ char *volatile p = "string1";
+ char *volatile r = "string2";
+ char *q = foo (p);
+ if (q != NULL)
+ {
+ if (strcmp (q, "string1/abcde"))
+ abort ();
+ memset (q, '\0', 14);
+ free (q);
+ }
+ q = bar (p);
+ if (q != NULL)
+ {
+ if (strcmp (q, "string1/abcde"))
+ abort ();
+ free (q);
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-7.c b/gcc/testsuite/gcc.dg/strlenopt-7.c
new file mode 100644
index 00000000000..6fd940d748b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-7.c
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+char buf[64];
+
+__attribute__((noinline, noclone)) size_t
+foo (void)
+{
+ char *p = memcpy (buf, "abcdefgh", 9);
+ /* This store can be optimized away as... */
+ *p = '\0';
+ /* ... the following strcat can be optimized into memcpy,
+ which overwrites that '\0'. */
+ strcat (p, "ijk");
+ /* This should be optimized into return 3. */
+ return strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+bar (char *p)
+{
+ char *r = strchr (p, '\0');
+ /* This store shouldn't be optimized away, because we
+ want to crash if p is e.g. a string literal. */
+ *r = '\0';
+ /* This strlen can be optimized into 0. */
+ return strlen (r);
+}
+
+int
+main ()
+{
+ char *volatile p = buf;
+ if (foo () != 3 || memcmp (buf, "ijk\0efgh\0", 10) != 0)
+ abort ();
+ if (bar (p) != 0 || memcmp (buf, "ijk\0efgh\0", 10) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
+/* { dg-final { scan-tree-dump-times "return 3;" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-8.c b/gcc/testsuite/gcc.dg/strlenopt-8.c
new file mode 100644
index 00000000000..3aaf660a12c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-8.c
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+/* Yes, there are people who write code like this. */
+
+__attribute__((noinline, noclone)) char *
+foo (int r)
+{
+ char buf[10] = "";
+ strcat (buf, r ? "r" : "w");
+ strcat (buf, "b");
+ return strdup (buf);
+}
+
+__attribute__((noinline, noclone)) char *
+bar (int r)
+{
+ char buf[10] = {};
+ strcat (buf, r ? "r" : "w");
+ strcat (buf, "b");
+ return strdup (buf);
+}
+
+int
+main ()
+{
+ char *q = foo (1);
+ if (q != NULL)
+ {
+ if (strcmp (q, "rb"))
+ abort ();
+ free (q);
+ }
+ q = bar (0);
+ if (q != NULL)
+ {
+ if (strcmp (q, "wb"))
+ abort ();
+ free (q);
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-9.c b/gcc/testsuite/gcc.dg/strlenopt-9.c
new file mode 100644
index 00000000000..6590d708ec7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-9.c
@@ -0,0 +1,109 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) char *
+fn1 (int r)
+{
+ char *p = r ? "a" : "bc";
+ /* String length for p varies, therefore strchr below isn't
+ optimized away. */
+ return strchr (p, '\0');
+}
+
+__attribute__((noinline, noclone)) size_t
+fn2 (int r)
+{
+ char *p, q[10];
+ strcpy (q, "abc");
+ p = r ? "a" : q;
+ /* String length for p varies, therefore strlen below isn't
+ optimized away. */
+ return strlen (p);
+}
+
+__attribute__((noinline, noclone)) size_t
+fn3 (char *p, int n)
+{
+ int i;
+ p = strchr (p, '\0');
+ /* strcat here can be optimized into memcpy. */
+ strcat (p, "abcd");
+ for (i = 0; i < n; i++)
+ if ((i % 123) == 53)
+ /* strcat here is optimized into strlen and memcpy. */
+ strcat (p, "efg");
+ /* The strlen here can't be optimized away, as in the loop string
+ length of p might change. */
+ return strlen (p);
+}
+
+char buf[64];
+
+__attribute__((noinline, noclone)) size_t
+fn4 (char *x, int n)
+{
+ int i;
+ size_t l;
+ char a[64];
+ char *p = strchr (x, '\0');
+ /* strcpy here is optimized into memcpy, length computed as p - x + 1. */
+ strcpy (a, x);
+ /* strcat here is optimized into memcpy. */
+ strcat (p, "abcd");
+ for (i = 0; i < n; i++)
+ if ((i % 123) == 53)
+ /* strcat here is optimized into strlen and memcpy. */
+ strcat (a, "efg");
+ /* The strlen should be optimized here into 4. */
+ l = strlen (p);
+ /* This stays strcpy. */
+ strcpy (buf, a);
+ return l;
+}
+
+int
+main ()
+{
+ volatile int l = 1;
+ char b[64];
+
+ if (memcmp (fn1 (l) - 1, "a", 2) != 0)
+ abort ();
+ if (memcmp (fn1 (!l) - 2, "bc", 3) != 0)
+ abort ();
+ if (fn2 (l) != 1 || fn2 (!l) != 3)
+ abort ();
+ memset (b, '\0', sizeof b);
+ memset (b, 'a', 3);
+ if (fn3 (b, 10) != 4 || memcmp (b, "aaaabcd", 8) != 0)
+ abort ();
+ if (fn3 (b, 128) != 7 || memcmp (b, "aaaabcdabcdefg", 15) != 0)
+ abort ();
+ if (fn3 (b, 256) != 10 || memcmp (b, "aaaabcdabcdefgabcdefgefg", 25) != 0)
+ abort ();
+ if (fn4 (b, 10) != 4
+ || memcmp (b, "aaaabcdabcdefgabcdefgefgabcd", 29) != 0
+ || memcmp (buf, "aaaabcdabcdefgabcdefgefg", 25) != 0)
+ abort ();
+ if (fn4 (b, 128) != 4
+ || memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcd", 33) != 0
+ || memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdefg", 32) != 0)
+ abort ();
+ if (fn4 (b, 256) != 4
+ || memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcdabcd", 37) != 0
+ || memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdabcdefgefg", 39) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
+/* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt.h b/gcc/testsuite/gcc.dg/strlenopt.h
new file mode 100644
index 00000000000..ef47e5ac9ad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt.h
@@ -0,0 +1,59 @@
+/* This is a replacement of needed parts from stdlib.h and string.h
+ for -foptimize-strlen testing, to ensure we are testing the builtins
+ rather than whatever the OS has in its headers. */
+
+#define NULL ((void *) 0)
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+void *malloc (size_t);
+void free (void *);
+char *strdup (const char *);
+size_t strlen (const char *);
+void *memcpy (void *__restrict, const void *__restrict, size_t);
+char *strcpy (char *__restrict, const char *__restrict);
+char *strcat (char *__restrict, const char *__restrict);
+char *strchr (const char *, int);
+void *memset (void *, int, size_t);
+int memcmp (const void *, const void *, size_t);
+int strcmp (const char *, const char *);
+#ifdef USE_GNU
+void *mempcpy (void *__restrict, const void *__restrict, size_t);
+char *stpcpy (char *__restrict, const char *__restrict);
+#endif
+
+#if defined(FORTIFY_SOURCE) && FORTIFY_SOURCE > 0 && __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, FORTIFY_SOURCE > 0)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+ return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
+strcpy (char *__restrict dest, const char *__restrict src)
+{
+ return __builtin___strcpy_chk (dest, src, bos (dest));
+}
+
+extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
+strcat (char *__restrict dest, const char *__restrict src)
+{
+ return __builtin___strcat_chk (dest, src, bos (dest));
+}
+
+# ifdef USE_GNU
+extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
+mempcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+ return __builtin___mempcpy_chk (dest, src, len, bos0 (dest));
+}
+
+extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
+stpcpy (char *__restrict dest, const char *__restrict src)
+{
+ return __builtin___stpcpy_chk (dest, src, bos (dest));
+}
+# endif
+#endif