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

            Bug ID: 83643
           Summary: missing strlen optimization for strcat with offset at
                    most the length of destination
           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: ---

All functions in the test program below are equivalent and can all be
transformed into the same object code.

Why would someone call strcat(d + n, s1) rather than simply strcat(d, s1)? 
Maybe in a naive/incomplete effort to "optimize" the call to avoid traversing
the initial string copied into d, instead of calling strcpy (d + n, s1).  Since
calling strcat (d + n, ...) doesn't make a whole lot of sense and could be an
indication of a bug, an alternative to enhancing the strlen pass and
implementing this optimization (or in addition to it), GCC could issue a
warning pointing it out.

$ cat a.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout a.c
void f0 (char *d, const char *s)
{
  __builtin_strcat (d, "123");
  __builtin_strcat (d, s);       // transformed into strcpy (d + 3, s)
}

void f1 (char *d, const char *s)
{
  __builtin_strcat (d, "123");
  __builtin_strcat (d + 1, s);   // same as strcat (d, s) but not transformed
}

void f2 (char *d, const char *s)
{
  __builtin_strcat (d, "123");
  __builtin_strcat (d + 2, s);   // not transformed
}

void fn (char *d, const char *s, unsigned n)
{
  __builtin_strcat (d, "123");

  if (n > __builtin_strlen (d))
    n = 0;

  __builtin_strcat (d + n, s);   // not transformed
}

;; Function f0 (f0, funcdef_no=0, decl_uid=1893, cgraph_uid=0, symbol_order=0)

f0 (char * d, const char * s)
{
  long unsigned int _3;
  char * _4;
  long unsigned int _8;
  char * _9;

  <bb 2> [local count: 1073741825]:
  _3 = __builtin_strlen (d_2(D));
  _4 = d_2(D) + _3;
  __builtin_memcpy (_4, "123", 4);
  _8 = _3 + 3;
  _9 = d_2(D) + _8;
  __builtin_strcpy (_9, s_6(D)); [tail call]
  return;

}



;; Function f1 (f1, funcdef_no=1, decl_uid=1897, cgraph_uid=1, symbol_order=1)

f1 (char * d, const char * s)
{
  char * _1;
  long unsigned int _4;
  char * _5;

  <bb 2> [local count: 1073741825]:
  _4 = __builtin_strlen (d_3(D));
  _5 = d_3(D) + _4;
  __builtin_memcpy (_5, "123", 4);
  _1 = d_3(D) + 1;
  __builtin_strcat (_1, s_7(D)); [tail call]
  return;

}



;; Function f2 (f2, funcdef_no=2, decl_uid=1901, cgraph_uid=2, symbol_order=2)

f2 (char * d, const char * s)
{
  char * _1;
  long unsigned int _4;
  char * _5;

  <bb 2> [local count: 1073741825]:
  _4 = __builtin_strlen (d_3(D));
  _5 = d_3(D) + _4;
  __builtin_memcpy (_5, "123", 4);
  _1 = d_3(D) + 2;
  __builtin_strcat (_1, s_7(D)); [tail call]
  return;

}



;; Function fn (fn, funcdef_no=3, decl_uid=1906, cgraph_uid=3, symbol_order=3)

fn (char * d, const char * s, unsigned int n)
{
  long unsigned int _1;
  long unsigned int _2;
  long unsigned int _8;
  char * _9;
  char * _15;
  char * prephitmp_16;

  <bb 2> [local count: 1073741825]:
  _8 = __builtin_strlen (d_7(D));
  _9 = d_7(D) + _8;
  __builtin_memcpy (_9, "123", 4);
  _1 = (long unsigned int) n_11(D);
  _2 = _8 + 3;
  if (_1 > _2)
    goto <bb 4>; [50.00%]
  else
    goto <bb 3>; [50.00%]

  <bb 3> [local count: 536870913]:
  _15 = d_7(D) + _1;

  <bb 4> [local count: 1073741825]:
  # prephitmp_16 = PHI <_15(3), d_7(D)(2)>
  __builtin_strcat (prephitmp_16, s_12(D)); [tail call]
  return;

}

Reply via email to