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;
}