1 /* { dg-do run } */
2 /* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
3 
4 #include "strlenopt.h"
5 
6 __attribute__((noinline, noclone)) char *
fn1(int r)7 fn1 (int r)
8 {
9   char *p = r ? "a" : "bc";
10   /* String length for p varies, therefore strchr below isn't
11      optimized away.  */
12   return strchr (p, '\0');
13 }
14 
15 __attribute__((noinline, noclone)) size_t
fn2(int r)16 fn2 (int r)
17 {
18   char *p, q[10];
19   strcpy (q, "abc");
20   p = r ? "a" : q;
21   /* String length for p varies, therefore strlen below isn't
22      optimized away.  */
23   return strlen (p);
24 }
25 
26 __attribute__((noinline, noclone)) size_t
fn3(char * p,int n)27 fn3 (char *p, int n)
28 {
29   int i;
30   p = strchr (p, '\0');
31   /* strcat here can be optimized into memcpy.  */
32   strcat (p, "abcd");
33   for (i = 0; i < n; i++)
34     if ((i % 123) == 53)
35       /* strcat here is optimized into strlen and memcpy.  */
36       strcat (p, "efg");
37   /* The strlen here can't be optimized away, as in the loop string
38      length of p might change.  */
39   return strlen (p);
40 }
41 
42 char buf[64];
43 
44 __attribute__((noinline, noclone)) size_t
fn4(char * x,int n)45 fn4 (char *x, int n)
46 {
47   int i;
48   size_t l;
49   char a[64];
50   char *p = strchr (x, '\0');
51   /* strcpy here is optimized into memcpy, length computed as p - x + 1.  */
52   strcpy (a, x);
53   /* strcat here is optimized into memcpy.  */
54   strcat (p, "abcd");
55   for (i = 0; i < n; i++)
56     if ((i % 123) == 53)
57       /* strcat here is optimized into strlen and memcpy.  */
58       strcat (a, "efg");
59   /* The strlen should be optimized here into 4.  */
60   l = strlen (p);
61   /* This stays strcpy.  */
62   strcpy (buf, a);
63   return l;
64 }
65 
66 int
main()67 main ()
68 {
69   volatile int l = 1;
70   char b[64];
71 
72   if (memcmp (fn1 (l) - 1, "a", 2) != 0)
73     abort ();
74   if (memcmp (fn1 (!l) - 2, "bc", 3) != 0)
75     abort ();
76   if (fn2 (l) != 1 || fn2 (!l) != 3)
77     abort ();
78   memset (b, '\0', sizeof b);
79   memset (b, 'a', 3);
80   if (fn3 (b, 10) != 4 || memcmp (b, "aaaabcd", 8) != 0)
81     abort ();
82   if (fn3 (b, 128) != 7 || memcmp (b, "aaaabcdabcdefg", 15) != 0)
83     abort ();
84   if (fn3 (b, 256) != 10 || memcmp (b, "aaaabcdabcdefgabcdefgefg", 25) != 0)
85     abort ();
86   if (fn4 (b, 10) != 4
87       || memcmp (b, "aaaabcdabcdefgabcdefgefgabcd", 29) != 0
88       || memcmp (buf, "aaaabcdabcdefgabcdefgefg", 25) != 0)
89     abort ();
90   if (fn4 (b, 128) != 4
91       || memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcd", 33) != 0
92       || memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdefg", 32) != 0)
93     abort ();
94   if (fn4 (b, 256) != 4
95       || memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcdabcd", 37) != 0
96       || memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdabcdefgefg", 39) != 0)
97     abort ();
98   return 0;
99 }
100 
101 /* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
102 /* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
103 /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
104 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
105 /* { dg-final { scan-tree-dump-times "strchr \\(" 3 "strlen" } } */
106 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
107 /* { dg-final { cleanup-tree-dump "strlen" } } */
108 /* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */
109 /* { dg-final { cleanup-tree-dump "optimized" } } */
110