1 /* { dg-do run } */
2 /* { dg-options "-O2 -fdump-tree-strlen" } */
3 
4 #include "strlenopt.h"
5 
6 __attribute__((noinline, noclone)) const char *
fn1(int x,int y)7 fn1 (int x, int y)
8 {
9   const char *p;
10   switch (x)
11     {
12     case 0:
13       p = "abcd";
14       /* Prevent cswitch optimization.  */
15       asm volatile ("" : : : "memory");
16       break;
17     case 1:
18       p = "efgh";
19       break;
20     case 2:
21       p = "ijkl";
22       break;
23     default:
24       p = "mnop";
25       break;
26     }
27   if (y)
28     /* strchr should be optimized into p + 4 here.  */
29     return strchr (p, '\0');
30   else
31     /* and strlen into 3.  */
32     return p + strlen (p + 1);
33 }
34 
35 __attribute__((noinline, noclone)) size_t
fn2(char * p,char * q)36 fn2 (char *p, char *q)
37 {
38   size_t l;
39   /* Both strcpy calls can be optimized into memcpy, strlen needs to stay.  */
40   strcpy (p, "abc");
41   p[3] = 'd';
42   l = strlen (p);
43   strcpy (q, p);
44   return l;
45 }
46 
47 __attribute__((noinline, noclone)) char *
fn3(char * p)48 fn3 (char *p)
49 {
50   char *c;
51   /* The strcpy call can be optimized into memcpy, strchr needs to stay,
52      strcat is optimized into memcpy.  */
53   strcpy (p, "abc");
54   p[3] = 'd';
55   c = strchr (p, '\0');
56   strcat (p, "efgh");
57   return c;
58 }
59 
60 int
main()61 main ()
62 {
63   int i;
64   char buf[64], buf2[64];
65   for (i = 0; i < 5; i++)
66     {
67       const char *p = "abcdefghijklmnop" + (i < 3 ? i : 3) * 4;
68       const char *q;
69       q = fn1 (i, 1);
70       if (memcmp (q - 4, p, 4) != 0 || q[0] != '\0')
71 	abort ();
72       q = fn1 (i, 0);
73       if (memcmp (q - 3, p, 4) != 0 || q[1] != '\0')
74 	abort ();
75     }
76   memset (buf, '\0', sizeof buf);
77   memset (buf + 4, 'z', 2);
78   if (fn2 (buf, buf2) != 6
79       || memcmp (buf, "abcdzz", 7) != 0
80       || memcmp (buf2, "abcdzz", 7) != 0)
81     abort ();
82   memset (buf, '\0', sizeof buf);
83   memset (buf + 4, 'z', 2);
84   if (fn3 (buf) != buf + 6 || memcmp (buf, "abcdzzefgh", 11) != 0)
85     abort ();
86   return 0;
87 }
88 
89 /* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
90 /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
91 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
92 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
93 /* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
94 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
95 /* { dg-final { cleanup-tree-dump "strlen" } } */
96