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