This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/81330] New: missing strlen optimization with intervening memcpy
- From: "msebor at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Wed, 05 Jul 2017 21:50:16 +0000
- Subject: [Bug tree-optimization/81330] New: missing strlen optimization with intervening memcpy
- Auto-submitted: auto-generated
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;
}