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