https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81330

            Bug ID: 81330
           Summary: missing strlen optimization with intervening memcpy
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

GCC eliminates redundant calls to strlen() with intervening calls to strcpy but
it misses an opportunity to do the same when the intervening call is to memcpy
instead.  In the test case below, since both strcpy and memcpy require that the
copies do not overlap, it's safe to assume that neither call modifies any part
of the source string, including the terminating nul, and so the second strlen
call can be replaced with the result of the first in both functions, not just
in f().  The strlen dump shows that GCC doesn't take advantage of this
guarantee in the memcpy case.

(The second strlen call in g is replaced with the result of the first in g when
memcpy is passed n0 + 1 as the size but I don't see why that should make a
difference.)

$ cat a.c && gcc -O2 -S -Wall -fdump-tree-strlen=/dev/stdout a.c
void f (char* d, const char* s)
{
  __SIZE_TYPE__ n0 = __builtin_strlen (s);

  __builtin_strcpy (d, s);

  __SIZE_TYPE__ n1 = __builtin_strlen (s);

  if (n0 != n1)
    __builtin_abort ();   // optimized
}

void g (char* d, const char* s)
{
  __SIZE_TYPE__ n0 = __builtin_strlen (s);

  __builtin_memcpy (d, s, n0);

  __SIZE_TYPE__ n1 = __builtin_strlen (s);

  if (n0 != n1)
    __builtin_abort ();   // not optimized
}


;; Function f (f, funcdef_no=0, decl_uid=1816, cgraph_uid=0, symbol_order=0)

f (char * d, const char * s)
{
  long unsigned int n1;
  long unsigned int n0;
  long unsigned int _8;

  <bb 2> [100.00%] [count: INV]:
  n0_3 = __builtin_strlen (s_2(D));
  _8 = n0_3 + 1;
  __builtin_memcpy (d_4(D), s_2(D), _8);
  n1_6 = n0_3;
  if (n0_3 != n1_6)
    goto <bb 3>; [0.04%] [count: 0]
  else
    goto <bb 4>; [99.96%] [count: INV]

  <bb 3> [0.04%] [count: 0]:
  __builtin_abort ();

  <bb 4> [99.96%] [count: INV]:
  return;

}



;; Function g (g, funcdef_no=1, decl_uid=1822, cgraph_uid=1, symbol_order=1)

g (char * d, const char * s)
{
  long unsigned int n1;
  long unsigned int n0;

  <bb 2> [100.00%] [count: INV]:
  n0_3 = __builtin_strlen (s_2(D));
  __builtin_memcpy (d_4(D), s_2(D), n0_3);
  n1_6 = __builtin_strlen (s_2(D));
  if (n0_3 != n1_6)
    goto <bb 3>; [0.04%] [count: 0]
  else
    goto <bb 4>; [99.96%] [count: INV]

  <bb 3> [0.04%] [count: 0]:
  __builtin_abort ();

  <bb 4> [99.96%] [count: INV]:
  return;

}

Reply via email to