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

            Bug ID: 81343
           Summary: missing strlen optimization with intervening strcat of
                    unknown strings
           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 is able to eliminate the second of a pair of strlen(src) with an unknown
string src even with an intervening call to strcpy(dst, src) with an unknown
dst.  This is possible because the strcpy call can be assumed not to modify the
source string.  However, GCC doesn't perform the same simplification when the
intervening call is one to strcat(dst, src), even though that call too can be
assumed not to modify str.  The test case below shows the difference.

From stepping through the code it looks to me like this is caused by the
handle_builtin_strcat() function in tree-ssa-strlen.c returning early in this
case, without retrieving the strinfo for the source string and setting the
dont_invalidate flag on it.

$ cat a.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout t.c
typedef __SIZE_TYPE__ size_t;

void f (char *d, const char *s)
{
   size_t n0 = __builtin_strlen (s);

   __builtin_strcpy (d, s);

   size_t n1 = __builtin_strlen (s);   // call eliminated

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

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

   __builtin_strcat (d, s);

   size_t n1 = __builtin_strlen (s);   // call not eliminated

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

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

f (char * d, const char * s)
{
  size_t 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); [tail call]
  return;

}



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

g (char * d, const char * s)
{
  size_t n1;
  size_t n0;

  <bb 2> [100.00%] [count: INV]:
  n0_3 = __builtin_strlen (s_2(D));
  __builtin_strcat (d_4(D), s_2(D));
  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