1 /* This test needs runtime that provides stpcpy and mempcpy functions.  */
2 /* { dg-do run { target *-*-linux* *-*-gnu* } } */
3 /* { dg-options "-O2 -fdump-tree-strlen" } */
4 /* Bionic targets don't have mempcpy */
5 /* { dg-require-effective-target non_bionic } */
6 
7 #define USE_GNU
8 #include "strlenopt.h"
9 
10 __attribute__((noinline, noclone)) char *
fn1(char * p,size_t * l1,size_t * l2)11 fn1 (char *p, size_t *l1, size_t *l2)
12 {
13   char *a = mempcpy (p, "abcde", 6);
14   /* This strlen needs to stay.  */
15   size_t la = strlen (a);
16   /* This strlen can be optimized into 5.  */
17   size_t lp = strlen (p);
18   *l1 = la;
19   *l2 = lp;
20   return a;
21 }
22 
23 __attribute__((noinline, noclone)) char *
fn2(char * p,const char * q,size_t * l1,size_t * l2,size_t * l3)24 fn2 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
25 {
26   /* This strlen needs to stay.  */
27   size_t lq = strlen (q);
28   char *a = mempcpy (p, q, lq + 1);
29   /* This strlen needs to stay.  */
30   size_t la = strlen (a);
31   /* This strlen can be optimized into lq.  */
32   size_t lp = strlen (p);
33   *l1 = lq;
34   *l2 = la;
35   *l3 = lp;
36   return a;
37 }
38 
39 __attribute__((noinline, noclone)) char *
fn3(char * p,size_t * l1,size_t * l2)40 fn3 (char *p, size_t *l1, size_t *l2)
41 {
42   char *a = stpcpy (p, "abcde");
43   /* This strlen can be optimized into 0.  */
44   size_t la = strlen (a);
45   /* This strlen can be optimized into 5.  */
46   size_t lp = strlen (p);
47   *l1 = la;
48   *l2 = lp;
49   return a;
50 }
51 
52 __attribute__((noinline, noclone)) char *
fn4(char * p,const char * q,size_t * l1,size_t * l2,size_t * l3)53 fn4 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
54 {
55   /* This strlen needs to stay.  */
56   size_t lq = strlen (q);
57   char *a = stpcpy (p, q);
58   /* This strlen can be optimized into 0.  */
59   size_t la = strlen (a);
60   /* This strlen can be optimized into lq.  */
61   size_t lp = strlen (p);
62   *l1 = lq;
63   *l2 = la;
64   *l3 = lp;
65   return a;
66 }
67 
68 __attribute__((noinline, noclone)) char *
fn5(char * p,const char * q,size_t * l1,size_t * l2)69 fn5 (char *p, const char *q, size_t *l1, size_t *l2)
70 {
71   char *a = stpcpy (p, q);
72   /* This strlen can be optimized into 0.  */
73   size_t la = strlen (a);
74   /* This strlen can be optimized into a - p.  */
75   size_t lp = strlen (p);
76   *l1 = la;
77   *l2 = lp;
78   return a;
79 }
80 
81 int
main()82 main ()
83 {
84   char buf[64];
85   const char *volatile q = "ABCDEFGH";
86   size_t l1, l2, l3;
87   memset (buf, '\0', sizeof buf);
88   memset (buf + 6, 'z', 7);
89   if (fn1 (buf, &l1, &l2) != buf + 6 || l1 != 7 || l2 != 5
90       || memcmp (buf, "abcde\0zzzzzzz", 14) != 0)
91     abort ();
92   if (fn2 (buf, q, &l1, &l2, &l3) != buf + 9 || l1 != 8 || l2 != 4 || l3 != 8
93       || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
94     abort ();
95   if (fn3 (buf, &l1, &l2) != buf + 5 || l1 != 0 || l2 != 5
96       || memcmp (buf, "abcde\0GH\0zzzz", 14) != 0)
97     abort ();
98   l3 = 0;
99   memset (buf, 'n', 9);
100   if (fn4 (buf, q, &l1, &l2, &l3) != buf + 8 || l1 != 8 || l2 != 0 || l3 != 8
101       || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
102     abort ();
103   memset (buf, 'm', 9);
104   if (fn5 (buf, q, &l1, &l2) != buf + 8 || l1 != 0 || l2 != 8
105       || memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
106     abort ();
107   return 0;
108 }
109 
110 /* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
111 /* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
112 /* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */
113 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
114 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
115 /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
116 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
117