| /* { 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 \\(" 2 "strlen1" } } */ |
| /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "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" } } */ |