1  /* { dg-do run } */
       2  /* { dg-options "-O2 -fdump-tree-strlen" } */
       3  
       4  #include "strlenopt.h"
       5  
       6  __attribute__((noinline, noclone)) size_t
       7  fn1 (char *p)
       8  {
       9    char *q;
      10    /* This can be optimized into memcpy and the size can be decreased to one,
      11       as it is immediately overwritten.  */
      12    strcpy (p, "z");
      13    q = strchr (p, '\0');
      14    *q = 32;
      15    /* This strlen can't be optimized away, string length is unknown here.  */
      16    return strlen (p);
      17  }
      18  
      19  __attribute__((noinline, noclone)) void
      20  fn2 (char *p, const char *z, size_t *lp)
      21  {
      22    char *q, *r;
      23    char buf[64];
      24    size_t l[10];
      25    /* The first strlen stays, all the strcpy calls can be optimized
      26       into memcpy and all other strlen calls and all strchr calls
      27       optimized away.  */
      28    l[0] = strlen (z);
      29    strcpy (buf, z);
      30    strcpy (p, "abcde");
      31    q = strchr (p, '\0');
      32    strcpy (q, "efghi");
      33    r = strchr (q, '\0');
      34    strcpy (r, "jkl");
      35    l[1] = strlen (p);
      36    l[2] = strlen (q);
      37    l[3] = strlen (r);
      38    strcpy (r, buf);
      39    l[4] = strlen (p);
      40    l[5] = strlen (q);
      41    l[6] = strlen (r);
      42    strcpy (r, "mnopqr");
      43    l[7] = strlen (p);
      44    l[8] = strlen (q);
      45    l[9] = strlen (r);
      46    memcpy (lp, l, sizeof l);
      47  }
      48  
      49  int
      50  main ()
      51  {
      52    char buf[64];
      53    size_t l[10];
      54    const char *volatile z = "ABCDEFG";
      55    memset (buf, '\0', sizeof buf);
      56    if (fn1 (buf) != 2 || buf[0] != 'z' || buf[1] != 32 || buf[2] != '\0')
      57      abort ();
      58    fn2 (buf, z, l);
      59    if (memcmp (buf, "abcdeefghimnopqr", 17) != 0)
      60      abort ();
      61    if (l[0] != 7)
      62      abort ();
      63    if (l[1] != 13 || l[2] != 8 || l[3] != 3)
      64      abort ();
      65    if (l[4] != 17 || l[5] != 12 || l[6] != 7)
      66      abort ();
      67    if (l[7] != 16 || l[8] != 11 || l[9] != 6)
      68      abort ();
      69    return 0;
      70  }
      71  
      72  /* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
      73  /* Some targets have BIGGEST_ALIGNMENT 8-bits, allowing fold_builtin_memory_op
      74     to expand the memcpy call at the end of fn2.  */
      75  /* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen1" { target { ! no_alignment_constraints } } } } */
      76  /* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { no_alignment_constraints} } } } */
      77  /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
      78  /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
      79  /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
      80  /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
      81  /* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen1" } } */
      82  /* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen1" } } */