https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81703
Bug ID: 81703 Summary: memcpy folding defeats strlen optimization 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: --- When a call to memcpy() copies a string of known length the gimple_fold_builtin_memcpy function transforms the call to a direct memory access. This transformation then prevents a subsequent strlen optimization that would otherwise readily take place. As a result, even simple examples like the one in the test case below are not optimized into optimal code. (In addition, the folding fails to consider the size of the destination and allows buffer overflow to go unnoticed -- this is the subject of bug 79220). I think this could be dealt in one of at least two ways: a) by enhancing the tree-ssa-strlen pass to recognize direct memory references (this alone won't help with bug 79220), or b) by deferring the folding until after the tree-ssa-strlen pass has had a chance to perform its sophisticate analysis and transformations. Between the two alternatives, I would expect b) to be the simpler solution and yield better results (it could also better handle bug 79220). $ cat a.c && gcc -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout a.c unsigned f (void) { char d[8]; const char s[] = "0123"; __builtin_strcpy (d, s); return __builtin_strlen (d); } unsigned g (void) // can be optimized the same as f() { char d[8]; const char s[] = "0123"; __builtin_memcpy (d, s, sizeof s); return __builtin_strlen (d); } ;; Function f (f, funcdef_no=0, decl_uid=1815, cgraph_uid=0, symbol_order=0) f () { <bb 2> [100.00%] [count: INV]: return 4; } ;; Function g (g, funcdef_no=1, decl_uid=1820, cgraph_uid=1, symbol_order=1) g () { const char s[5]; char d[8]; long unsigned int _1; unsigned int _5; <bb 2> [100.00%] [count: INV]: s = "0123"; MEM[(char * {ref-all})&d] = MEM[(char * {ref-all})&s]; _1 = __builtin_strlen (&d); _5 = (unsigned int) _1; d ={v} {CLOBBER}; s ={v} {CLOBBER}; return _5; }