/* { 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" } } */