1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
/* { 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 "strlen1" } } */
/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" } } */
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
|