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